// ========== Copyright Header Begin ==========================================
// 
// OpenSPARC T1 Processor File: Fpu.cc
// Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// 
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// 
// The above named program is distributed in the hope that it will be 
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// 
// ========== Copyright Header End ============================================
/************************************************************************
**
**  Copyright (C) 2002, Sun Microsystems, Inc.
**
**  Sun considers its source code as an unpublished, proprietary
**  trade secret and it is available only under strict license provisions.
**  This copyright notice is placed here only to protect Sun in the event
**  the source is deemed a published work. Disassembly, decompilation,
**  or other means of reducing the object code to human readable form
**  is prohibited by the license agreement under which this code is
**  provided to the user or company in possession of this copy."
**
*************************************************************************/

#include "Fgu/Fpu.h"
#include "V9/V9_Trap.h"
#include "StdMacros.h"
#include "softfloat.h"
#include "Exception.h"
#include "BasicTrap.h"
#include <sstream>
#include <iomanip>

using namespace std;
using namespace Riesling;


#define INC_PC_AND_NPC()                         \
{                                                \
    asPtr_->setPc(asPtr_->getNpc());             \
    asPtr_->setNpc(asPtr_->getNpc() + 4);        \
}




Fpu::Fpu() : throw_fp_exception_other_(false)
{
  pstate_tct_enabled_ = false;
  pstate_tct_launch_ = false;
}

Fpu::Fpu( const Fpu & orig )
{
    // Replace the following line with your function body.
    RIESLING_THROW_DOMAIN_ERROR( "Unimplemented function." );
}

Fpu::~Fpu()
{}

const Fpu &Fpu::operator=( const Fpu & rhs )
{
  pstate_tct_enabled_ = false;
  pstate_tct_launch_ = false;
    return *this;
}

bool Fpu::operator==( const Fpu & rhs ) const
{
    // Replace the following line with your function body.
    RIESLING_THROW_DOMAIN_ERROR( "Unimplemented function." );
    return false;
}

string Fpu::toString() const
{
    // Replace the following line with your function body.
    RIESLING_THROW_DOMAIN_ERROR( "Unimplemented function." );

    return "";
}


bool Fpu::fpDisabled()
{
    uint32_t   fef, pef;
    bool       result;

    result = false;

    fef    = (uint32_t ) asPtr_->getFprsRegPtr()->getFEF();
    pef    = (uint32_t ) asPtr_->getPstateRegPtr()->getPEF();

    if ( (fef & pef) == 0 )
	result = true;

    return result;
}

bool Fpu::executeInstr( InstructionWord &iw, V9_ArchState *archStatePtr ) throw( BasicTrap & )
{
    uint32_t    op1, op2, op3, opf;
    bool        result;

    result = false;

    asPtr_   = archStatePtr;
    fregPtr_ = archStatePtr->getFloatRegisterFilePtr();

    op1  = iw.op();
    op2  = iw.op2();
    op3  = iw.op3() & 0x7;

    opf  = iw.opf();

    switch (op1) {

	case OP1_00:
	{
	    switch (op2) {
		case OP2_101:   result = execute_f2d_instr( iw );   break;
		case OP2_110:   result = execute_f2c_instr( iw );   break;
		default:        result = false;   break;
	    }
	    break;
	}   // OP1_00

	case OP1_01:
	{
	    result = false;
	    break;
	}

	case OP1_10:
	{
	    switch (op2) {

		case OP2_101:
		{
		    switch (op3) {

			case OP3_100:
			{
			    result = execute_f4b_instr( iw );
			    break;
			}
			default:
			{
			    result = false;
			    break;
			}
		    }
		    break;
		}   // case OP2_101

		case OP2_110:
		{
		    switch (op3) {

			case OP3_100:
			{
			    if ( (opf & OPF_0_01XX_XXXX_MASK) == OPF_0_01XX_XXXX ) {

				result = execute_f3n_instr( iw );

			    } else {

				result = execute_f3l_instr( iw );
			    }
			    break;
			}

			case OP3_101:
			{
			    if ( (opf & OPF_X_0101_XXXX_MASK) == OPF_X_0101_XXXX ) {

				result = execute_f3m_instr( iw );

			    } else if ( (opf & OPF_0_XXXX_01XX_MASK) == OPF_0_XXXX_01XX ) {

				result = execute_f4c_instr( iw );

			    } else {
				result = execute_f4d_instr( iw );
			    }
			    break;
			}

			default:
			{
			    result = false;
			    break;
			}
		    }   // switch OP1_10,OP2_110,op3
		    break;

		}   // case OP2_110

		default:
		{
		    result = false;
		    break;
		}

	    }   // switch OP1_10,op2
	    break;

	}   // case OP1_10

	case OP1_11:
	default:
	{
	    result = false;
	    break;
	}
    }   // switch op1

#if 0				// Let it proceed to throw ILLEGAL_INSTRUCTION
    if (result == false) {
	if ( (op1 == 0x2) && ( (iw.op3() == 0x34) || (iw.op3() == 0x35) ) ) {

	    if ( fpDisabled() ) {
		// setFpDirtyBits( iw, dest_type );
		RIESLING_TRAP( FP_DISABLED_TRAP );
	    }

	    asPtr_->getFsrRegPtr()->setFTT( FTT_UNIMPLEMENTED_FPOP );
	    RIESLING_TRAP( FP_EXCEPTION_OTHER_TRAP );
	}
    }
#endif

    return result;

}   // execute


void Fpu::read_src1_reg( InstructionWord    &iw,
		    enum op_reg_type_e  op_reg_type,
		    uint64_t            qp_value[2],
		    uint64_t           *dp_value,
		    uint32_t           *sp_value,
		    int                *trap_status)
{
    uint32_t   ftt;

    switch ( op_reg_type ) {

	case INT_TYPE:
	    *dp_value = asPtr_->getRegisterFilePtr()->get( iw.rs1() );
	    break;

	case SP_TYPE:
	    *sp_value = fregPtr_->getSpfp( iw.rs1() );
	    break;

	case DP_TYPE:
	    *dp_value = fregPtr_->getDpfp( iw.rs1() );
	    break;

	case QP_TYPE:
	{
	    if (iw.rs1() & 0x2) {

		ftt = FTT_INVALID_FP_REGISTER;
		Fpu::asPtr_->getFsrRegPtr()->setFTT(ftt);     // Write to the floating-point trap type

		*trap_status = FP_EXCEPTION_OTHER_TRAP;
		return;
	    }
	    qp_value[0] = fregPtr_->getQuadHigh( iw.rs1() );
	    qp_value[1] = fregPtr_->getQuadLow( iw.rs1() );
	    break;
	}

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

}   // read_src1_reg


void Fpu::read_src2_reg( InstructionWord    &iw,
		    enum op_reg_type_e  op_reg_type,
		    uint64_t            qp_value[2],
		    uint64_t           *dp_value,
		    uint32_t           *sp_value,
		    int                *trap_status)
{
    uint32_t   ftt;

    switch ( op_reg_type ) {

	case INT_TYPE:
	    *dp_value = asPtr_->getRegisterFilePtr()->get( iw.rs2() );
	    break;

	case SP_TYPE:
	    *sp_value = fregPtr_->getSpfp( iw.rs2() );
	    break;

	case DP_TYPE:
	    *dp_value = fregPtr_->getDpfp( iw.rs2() );
	    break;

	case QP_TYPE:
	    if (iw.rs2() & 0x2) {
		ftt = FTT_INVALID_FP_REGISTER;
		Fpu::asPtr_->getFsrRegPtr()->setFTT(ftt);     // Write to the floating-point trap type

		*trap_status = FP_EXCEPTION_OTHER_TRAP;
		return;
	    }
	    qp_value[0] = fregPtr_->getQuadHigh( iw.rs2() );
	    qp_value[1] = fregPtr_->getQuadLow( iw.rs2() );
	    break;

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

}   // read_src2_reg


void Fpu::setFpDirtyBits( InstructionWord &iw, enum op_reg_type_e op_reg_type )
{
    switch ( op_reg_type ) {
	case SP_TYPE:
	{
	    if ( iw.rd() < 32 )
		asPtr_->getFprsRegPtr()->setDL(1);
	    else
		asPtr_->getFprsRegPtr()->setDU(1);
	    break;
	}

	case DP_TYPE:
	{
	    if ( iw.rd() & 0x1 )
		asPtr_->getFprsRegPtr()->setDU(1);
	    else
		asPtr_->getFprsRegPtr()->setDL(1);
	    break;
	}

	case QP_TYPE:
	{
	    if ( iw.rd() & 0x1 )
		asPtr_->getFprsRegPtr()->setDU(1);
	    else
		asPtr_->getFprsRegPtr()->setDL(1);
	    break;
	}
    }
}

void Fpu::write_dest_reg( InstructionWord	&iw,
		     uint64_t		qp_value[2],
		     uint64_t		*dp_value,
		     uint32_t		*sp_value,
		     bool  		write_rd_reg,
		     enum op_reg_type_e	op_reg_type,
		     int  		*trap_status)
{
    uint32_t   ftt;

    switch ( op_reg_type ) {

	case SP_TYPE:
	{
	    if (write_rd_reg) {

		fregPtr_->setSpfp( iw.rd(), *sp_value );
		setFpDirtyBits( iw, op_reg_type );

	    } else {
	       *sp_value = fregPtr_->getSpfp( iw.rd() );
	    }
	    break;
	}

	case DP_TYPE:
	{
	    if (write_rd_reg) {

	        fregPtr_->setDpfp( iw.rd(), *dp_value );
		setFpDirtyBits( iw, op_reg_type );

	    } else {
	       *dp_value = fregPtr_->getDpfp( iw.rd() );
	    }
	    break;
	}

	case QP_TYPE:
	{
	    if (iw.rd() & 0x2) {
		ftt = FTT_INVALID_FP_REGISTER;
		Fpu::asPtr_->getFsrRegPtr()->setFTT(ftt);     // Write to the floating-point trap type

		*trap_status = FP_EXCEPTION_OTHER_TRAP;
		return;
	    }

	    if (write_rd_reg) {

	        fregPtr_->setQuadHigh( iw.rd(), qp_value[0] );
	        fregPtr_->setQuadLow(  iw.rd(), qp_value[1] );

		setFpDirtyBits( iw, op_reg_type );

	    } else {
	       qp_value[0] = fregPtr_->getQuadHigh( iw.rd() );
	       qp_value[1] = fregPtr_->getQuadHigh( iw.rd() );
	    }
	    break;
	}

	case INT_TYPE:
	{
	    if (write_rd_reg) {
		asPtr_->getRegisterFilePtr()->set( iw.rd(), *dp_value );
	    } else {
		*dp_value = asPtr_->getRegisterFilePtr()->get( iw.rd() );
	    }
	    break;
	}

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

}   // write_dest_reg


void Fpu::access_decoded_ccs( int access_xcc, bool *z, bool *n, bool *c, bool *v, bool read_reg )
{
    uint64_t   value;
    uint64_t   ccs;

    V9_CcrReg   *ccrPtr = asPtr_->getCcrRegPtr();

    if ( read_reg ) {
	if (access_xcc == ICC_ACCESS) {
	   value = ccrPtr->getICodes();
	} else {
	   value = ccrPtr->getXCodes();
	}
	*c = ( value >> 0 ) & MASK1;
	*v = ( value >> 1 ) & MASK1;
	*z = ( value >> 2 ) & MASK1;
	*n = ( value >> 3 ) & MASK1;
    } else {
	ccs = ( *n << 3 ) | ( *z << 2 ) | ( *v << 1 ) | ( *c << 0 );
	if (access_xcc == ICC_ACCESS) {
	    ccrPtr->setICodes(ccs);
	} else {
	    ccrPtr->setXCodes(ccs);
	}
    }
}


void Fpu::access_decoded_fccs( int fcc_num, bool *e, bool *l, bool *g, bool *u, bool read_reg )
{
    uint64_t    value;
    int         pos, size;

    V9_FsrReg   *fsrPtr = asPtr_->getFsrRegPtr();

    if (read_reg) {

	switch ( fcc_num ) {
	    case 0:   value = fsrPtr->getFCC0();   break;
	    case 1:   value = fsrPtr->getFCC1();   break;
	    case 2:   value = fsrPtr->getFCC2();   break;
	    case 3:   value = fsrPtr->getFCC3();   break;
	    default:
	    {
		RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
		break;
	    }
	}

	*e = false;
	*l = false;
	*g = false;
	*u = false;

	switch ( value ) {
	    case 0:    *e = true;    break;
	    case 1:    *l = true;    break;
	    case 2:    *g = true;    break;
	    case 3:    *u = true;    break;
	    default:
	    {
		RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
		break;
	    }
	}

    } else {

	value = ( *u << 3 ) | ( *g << 2 ) | ( *l << 1 ) | ( *e << 0 );

	switch ( value ) {
	    case 1:    value = 0;    break;
	    case 2:    value = 1;    break;
	    case 4:    value = 2;    break;
	    case 8:    value = 3;    break;
	    default:
	    {
		RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
		break;
	    }
	}

	switch ( fcc_num ) {
	    case 0:   fsrPtr->setFCC0(value);   break;
	    case 1:   fsrPtr->setFCC1(value);   break;
	    case 2:   fsrPtr->setFCC2(value);   break;
	    case 3:   fsrPtr->setFCC3(value);   break;
	    default:
	    {
		RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
		break;
	    }
	}
    }
}



fp_op_type Fpu::fpu_optype( enum op_reg_type_e src_type, uint64_t qp_value[2], uint64_t dp_value, uint32_t sp_value )
{
    // Determine what kind of floating-point number we have

    fp_op_type   num_type = FP_OP_NONE;

    // Switch based on the type (single, double or quad precision)
    // All cases are identical for different types, they just use different masks

    switch ( src_type ) {

	case SP_TYPE:
	{
	    if ((sp_value & ~(SIGN_MASK_32)) == 0) {

		// Zero

		if ((sp_value & SIGN_MASK_32) == SIGN_MASK_32) {
		    num_type = FP_OP_NZERO;
		} else {
		    num_type = FP_OP_PZERO;
		}

	    } else if ( ((sp_value & EXP_MASK_32) == 0) && ((sp_value & MANT_MASK_32) != 0) ) {

		// Subnormal number

		if ((sp_value & SIGN_MASK_32) != SIGN_MASK_32) {
		    num_type = FP_OP_PSUBNORMAL;
		} else {
		    num_type = FP_OP_NSUBNORMAL;
		}

	    } else if ( ((sp_value & EXP_MASK_32) != 0) && ((sp_value & EXP_MASK_32) != EXP_MASK_32) ) {

		// Normal number

		num_type = FP_OP_NORMAL;

	    } else if ( ((sp_value & EXP_MASK_32) == EXP_MASK_32) && ((sp_value & MANT_MASK_32) != 0) ) {

		// NAN

		if ((sp_value & QNAN_MASK_32) == QNAN_MASK_32) {
		    num_type = FP_OP_QNAN;       // quiet NAN
		} else {
		    num_type = FP_OP_SNAN;       // signalling NAN
		}

	    } else if ( ((sp_value & EXP_MASK_32) == EXP_MASK_32) && ((sp_value & MANT_MASK_32) == 0) ) {

		// Infinity

		num_type = FP_OP_INF;

	    } else {                    // Floating point number other than cases above (there shouldn't be any)
		RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    }
	    break;

	}   // case SP_TYPE


	case DP_TYPE:
	{
	    if ( (dp_value & ~(SIGN_MASK_64)) == 0 ) {

		// Zero

		if ((dp_value & SIGN_MASK_64) == SIGN_MASK_64) {
		    num_type = FP_OP_NZERO;
		} else {
		    num_type = FP_OP_PZERO;
		}

	    } else if ( ((dp_value & EXP_MASK_64) == 0) && ((dp_value & MANT_MASK_64) != 0) ) {

		// Subnormal number

		if ((dp_value & SIGN_MASK_64) != SIGN_MASK_64) {
		    num_type = FP_OP_PSUBNORMAL;
		} else {
		    num_type = FP_OP_NSUBNORMAL;
		}

	    } else if ( ((dp_value & EXP_MASK_64) != 0) && ((dp_value & EXP_MASK_64) != EXP_MASK_64) ) {

		// Normal number

		num_type = FP_OP_NORMAL;

	    } else if ( ((dp_value & EXP_MASK_64) == EXP_MASK_64) && ((dp_value & MANT_MASK_64) != 0) ) {

		// NAN

		if ((dp_value & QNAN_MASK_64) == QNAN_MASK_64) {
		    num_type = FP_OP_QNAN;
		} else {
		    num_type = FP_OP_SNAN;
		}

	    } else if ( ((dp_value & EXP_MASK_64) == EXP_MASK_64) && ((dp_value & MANT_MASK_64) == 0) ) {

		// Infinity

		num_type = FP_OP_INF;

	    } else {
		RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    }
	    break;

	}   // case DP_TYPE


	case QP_TYPE:
	{
	    if ( ((qp_value[0] & ~(SIGN_MASK_128H)) == 0) && (qp_value[1] == 0) ) {

		// Zero

		if ( (qp_value[0] & SIGN_MASK_128H) == SIGN_MASK_128H) {
		    num_type = FP_OP_NZERO;
		} else {
		    num_type = FP_OP_PZERO;
		}
	    }
	    else if ( ((qp_value[0] & EXP_MASK_128H) == 0) &&
		      ( ((qp_value[0] & MANT_MASK_128H) != 0) || ((qp_value[1] & MANT_MASK_128L) != 0) ) ) {

		// Subnormal number

		if ( (qp_value[0] & SIGN_MASK_128H) != (SIGN_MASK_128H)) {
		    num_type = FP_OP_PSUBNORMAL;
		} else {
		    num_type = FP_OP_NSUBNORMAL;
		}

	    } else if ( ((qp_value[0] & EXP_MASK_128H) != 0) && ((qp_value[0] & EXP_MASK_128H) != EXP_MASK_128H) ) {

		// Normal number

		num_type = FP_OP_NORMAL;

	    } else if ( ((qp_value[0] & EXP_MASK_128H) == EXP_MASK_128H) &&
		        ( ((qp_value[0] & MANT_MASK_128H) != 0) || ((qp_value[1] & MANT_MASK_128L) != 0) ) )  {

		// NAN

		if ( (qp_value[0] & QNAN_MASK_128H) == QNAN_MASK_128H ) {
		    num_type = FP_OP_QNAN;
		} else {
		    num_type = FP_OP_SNAN;
		}

	    } else if ( ((qp_value[0] & EXP_MASK_128H) == EXP_MASK_128H) &&
			((qp_value[0] & MANT_MASK_128H) == 0) &&
			((qp_value[1] & MANT_MASK_128L) == 0) )   {

		// Infinity

		num_type = FP_OP_INF;

	    } else {
		RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    }
	    break;

	}   // case QP_TYPE

	case INT_TYPE:
	case UNKNOWN_TYPE:
	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    return num_type;

}   // fpu_optype



uint64_t Fpu::determine_exp( enum op_reg_type_e src_type, uint64_t qp_value[2], uint64_t *dp_value, uint32_t *sp_value )
{
    uint64_t   exp = 0;

    switch (src_type) {
	case SP_TYPE:   exp = (EXP_MASK_32 & *sp_value)     >> SP_EXP_SHIFT;   break;
	case DP_TYPE:   exp = (EXP_MASK_64 & *dp_value)     >> DP_EXP_SHIFT;   break;
	case QP_TYPE:   exp = (EXP_MASK_128H & qp_value[0]) >> QP_EXP_SHIFT;   break;
	default:        exp = 0;   break;
    }

    return exp;

}   // determine_exp


bool Fpu::isUnimplementedV9Instruction( InstructionWord &iw, instr_e instr_type )
{
    return false;
}

int Fpu::fpu_preprocess( InstructionWord	&iw,
		     instr_e             instr_type,
		     uint64_t		 src1_qp_value[2],
		     uint64_t		*src1_dp_value,
		     uint32_t		*src1_sp_value,
		     fp_op_type          src1_fpop_type,
		     uint64_t		 src2_qp_value[2],
		     uint64_t		*src2_dp_value,
		     uint32_t		*src2_sp_value,
		     fp_op_type          src2_fpop_type )
{
    uint64_t   roundingMode;
    uint64_t   fsr_ns;

    // Determine mode

    fsr_ns = asPtr_->getFsrRegPtr()->getNS();

    if (fsr_ns == 1) {
	RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
    }

    // Clear out SoftFloat exceptions

    float_exception_flags = 0;

    // Set SoftFloat rounding mode . . .

    if ( ( instr_type == FSTOX  ) || ( instr_type == FSTOI  ) || ( instr_type == FDTOX  ) ||
         ( instr_type == FDTOI  ) || ( instr_type == FQTOX  ) || ( instr_type == FQTOI  ) || ( instr_type == SFSTOI ) ) {

        roundingMode = 1;   // Always 'round toward 0' for 'cvt float to int' instrs

    } else {

        // Determine which rounding mode we should be using

	roundingMode = asPtr_->getFsrRegPtr()->getRD();
    }

    float_rounding_mode = (uint32_t) roundingMode;

    return NO_TRAP;

}   // fpu_preprocess


float128 Fpu::iss_q_to_sf_q( uint64_t	qp_value[2] )
{
    float128   sf_q;

    sf_q.high = qp_value[0];
    sf_q.low  = qp_value[1];

    return sf_q;
}

void Fpu::sf_q_to_iss_q( float128 sf_q, uint64_t qp_value[2] )
{
    qp_value[0] = sf_q.high;
    qp_value[1] = sf_q.low;
}

uint64_t Fpu::nan_stod(uint32_t p_val)
{
    uint64_t   r_val;
    
    r_val  = ( (uint64_t) (p_val & MANT_MASK_32) ) << 29;   // Mantissa

    r_val |= EXP_MASK_64;                                    // Exponent

    if (p_val & SIGN_MASK_32) {                              // Sign
	r_val |= SIGN_MASK_64;
    }

    return r_val;
}


uint32_t Fpu::nan_dtos(uint64_t p_val)
{
    uint32_t   r_val;
    
    r_val  = (uint32_t ) ( (p_val & MANT_MASK_64) >> 29 );   // Mantissa

    r_val |= EXP_MASK_32;                    // Exponent

    if (p_val & SIGN_MASK_64) {              // Sign
	r_val |= SIGN_MASK_32;
    }

    return r_val;
}

void Fpu::nan_dtoq( uint64_t p_val, uint64_t r_val[2] )
{
    r_val[0] = (p_val & MANT_MASK_64) >> 4;   // Mantissa
    r_val[1] = (p_val & 0xF) << 60;

    r_val[0] |= EXP_MASK_128H;                // Exponent

    if (p_val & SIGN_MASK_64) {               // Sign
	r_val[0] |= SIGN_MASK_128H;
    }
}

uint64_t Fpu::nan_qtod( uint64_t p_val[2] )
{
    uint64_t   r_val;

    r_val  = ((p_val[0] & MANT_MASK_128H) << 4);   // Mantissa
    r_val |= (p_val[1] >> 60);

    r_val |= EXP_MASK_64;                          // Exponent

    if (p_val[0] & SIGN_MASK_128H) {               // Sign
	r_val |= SIGN_MASK_64;
    }

    return r_val;
}

void Fpu::nan_stoq(uint32_t p_val, uint64_t r_val[2])
{
    nan_dtoq(nan_stod(p_val), r_val);
}

uint32_t Fpu::nan_qtos(uint64_t p_val[2])
{
    return nan_dtos(nan_qtod(p_val));
}


void Fpu::nan_transformation( enum op_reg_type_e    src_type,
			 uint64_t	       src_qp_value[2],
			 uint64_t	       src_dp_value,
			 uint32_t	       src_sp_value,
			 enum op_reg_type_e    dest_type,
			 uint64_t	       rd_qp_value[2],
			 uint64_t	      *rd_dp_value,
			 uint32_t	      *rd_sp_value,
			 bool                  qnan)
{
    if ( (src_type == SP_TYPE) && (dest_type == DP_TYPE)  ) {
	*rd_dp_value = nan_stod(src_sp_value);
	if (qnan) {
	    *rd_dp_value |= QNAN_MASK_64;
	} else {
	    *rd_dp_value &= ~QNAN_MASK_64;
	}
    } else if ( (src_type == DP_TYPE) && (dest_type == SP_TYPE) ) {
	*rd_sp_value = nan_dtos(src_dp_value);
	if (qnan) {
	    *rd_sp_value |= QNAN_MASK_32;
	} else {
	    *rd_dp_value &= ~QNAN_MASK_32;
	}
    } else if ( (src_type == DP_TYPE) && (dest_type == QP_TYPE) ) {
	nan_dtoq(src_dp_value, rd_qp_value);
	if (qnan) {
	    rd_qp_value[0] |= QNAN_MASK_128H;
	} else {
	    rd_qp_value[0] &= ~QNAN_MASK_128H;
	}
    } else if ( (src_type == QP_TYPE) && (dest_type == DP_TYPE) ) {
	*rd_dp_value = nan_qtod(src_qp_value);
	if (qnan) {
	    *rd_dp_value |= QNAN_MASK_64;
	} else {
	    *rd_dp_value &= ~QNAN_MASK_64;
	}
    } else if ( (src_type == SP_TYPE) && (dest_type == QP_TYPE) ) {
	nan_stoq(src_sp_value, rd_qp_value);
	if (qnan) {
	    rd_qp_value[1] |= QNAN_MASK_128H;
	} else {
	    rd_qp_value[1] &= ~QNAN_MASK_128H;
	}
    } else if ( (src_type == QP_TYPE) && (dest_type == SP_TYPE) ) {
	*rd_sp_value = nan_qtos(src_qp_value);
	if (qnan) {
	    *rd_sp_value |= QNAN_MASK_32;
	} else {
	    *rd_sp_value &= ~QNAN_MASK_32;
	}
    } else {

	*rd_sp_value = src_sp_value | QNAN_MASK_32;
	*rd_dp_value = src_dp_value | QNAN_MASK_64;

	rd_qp_value[0] = src_qp_value[0] | QNAN_MASK_128H;
	rd_qp_value[1] = src_qp_value[1];
    }

}   // nan_transformation


bool Fpu::nan_postprocess( enum op_reg_type_e src1_type,
                 fp_op_type        src1_fpop_type,
		 uint64_t	   src1_qp_value[2],
		 uint64_t	   src1_dp_value,
		 uint32_t	   src1_sp_value,

		 enum op_reg_type_e src2_type,
		 fp_op_type        src2_fpop_type,
		 uint64_t	   src2_qp_value[2],
		 uint64_t	   src2_dp_value,
		 uint32_t	   src2_sp_value,

		 enum op_reg_type_e dest_type,
		 uint64_t	   rd_qp_value[2],
		 uint64_t	   *rd_dp_value,
		 uint32_t	   *rd_sp_value )
{
    uint64_t result64;

    bool   r_nan = false;

    /* This is based on the table in B.2 of the Sparc Manual, pg 245 */
    // The cases below are done in a specific order so to make sure the
    // proper cases fall through while the correct ones are caught


    // To catch column 2

    if (src2_fpop_type == FP_OP_QNAN) {
	if (src1_fpop_type == FP_OP_SNAN) {
	    // return QSNaN1
	    nan_transformation( src1_type, src1_qp_value, src1_dp_value, src1_sp_value,
				dest_type, rd_qp_value, rd_dp_value, rd_sp_value, true);
	    r_nan = true;
	} else {
	    // return QNaN2
	    nan_transformation( src2_type, src2_qp_value, src2_dp_value, src2_sp_value,
				dest_type, rd_qp_value, rd_dp_value, rd_sp_value, true);
	    r_nan = true;
	}
    } else if (src2_fpop_type == FP_OP_SNAN) { // To catch column 3
	// return QSNaN2
	nan_transformation( src2_type, src2_qp_value, src2_dp_value, src2_sp_value,
			    dest_type, rd_qp_value, rd_dp_value, rd_sp_value, true);
	r_nan = true;
    } else if (src1_fpop_type == FP_OP_QNAN) { // Catch row 3 except that column 2 & 3 have been
					       // eliminated above only will catch column 1
    // return QNaN1
	nan_transformation( src1_type, src1_qp_value, src1_dp_value, src1_sp_value,
			    dest_type, rd_qp_value, rd_dp_value, rd_sp_value, true);
	r_nan = true;
    } else if (src1_fpop_type == FP_OP_SNAN) { // Catch row 4 except that column 2 & 3 have been
                                               // eliminated above only will catch column 1
	// return QSNaN1
	nan_transformation( src1_type, src1_qp_value, src1_dp_value, src1_sp_value,
			    dest_type, rd_qp_value, rd_dp_value, rd_sp_value, true);
	r_nan = true;
    } else {
	r_nan = false;
    }

    return r_nan; // Return true if we manipulated the return value

}   // nan_postprocess


bool Fpu::float64_nan( uint64_t fvalue )
{
    bool       result;
    uint64_t   dummy_qp[2];
    uint32_t   dummy_sp;

    fp_op_type   type;

    result      = false;

    dummy_sp    = 0;
    dummy_qp[0] = 0;
    dummy_qp[1] = 0;

    type = fpu_optype( DP_TYPE, dummy_qp, fvalue, dummy_sp );

    if ( (type == FP_OP_QNAN) || (type == FP_OP_SNAN) )
	result = true;
    else
	result = false;

    return result;
}


bool Fpu::float32_nan( uint32_t fvalue )
{
    bool       result;
    uint64_t   dummy_qp[2];
    uint64_t   dummy_dp;

    fp_op_type   type;

    result      = false;

    dummy_dp    = 0;
    dummy_qp[0] = 0;
    dummy_qp[1] = 0;

    type = fpu_optype( SP_TYPE, dummy_qp, dummy_dp, fvalue );

    if ( (type == FP_OP_QNAN) || (type == FP_OP_SNAN) )
	result = true;
    else
	result = false;

    return result;
}

long long Fpu::float32_to_int64_sparc( float32 fvalue )
{
    long long   llvalue;

    llvalue = float32_to_int64(fvalue);

    // check for negative NaN

    if ( ((fvalue & EXP_MASK_32) == EXP_MASK_32) && ((fvalue & MANT_MASK_32) != 0) && ((fvalue & SIGN_MASK_32) != 0) ) {

	llvalue = SIGN_MASK_64;
    }

    return llvalue;
}

long long Fpu::float64_to_int64_sparc(float64 fvalue)
{
    long long   llvalue;
    
    llvalue = float64_to_int64(fvalue);

    /* check for negative NaN */

    if ( ((fvalue & EXP_MASK_64) == EXP_MASK_64) && ((fvalue & MANT_MASK_64) != 0) && ((fvalue & SIGN_MASK_64) != 0) ) {

	llvalue = SIGN_MASK_64;
    }

    return llvalue;
}

long Fpu::float32_to_int32_sparc(float32 fvalue)
{
    long   lvalue;
    
    lvalue = float32_to_int32(fvalue);

    /* check for negative NaN */

    if ( ((fvalue & EXP_MASK_32) == EXP_MASK_32) && ((fvalue & MANT_MASK_32) != 0) && ((fvalue & SIGN_MASK_32) != 0) ) {

	lvalue = SIGN_MASK_32;
    }

    return lvalue;
}

long Fpu::float64_to_int32_sparc(float64 fvalue)
{
    long   lvalue;
    
    lvalue = float64_to_int32(fvalue);

    /* check for negative NaN */

    if ( ((fvalue & EXP_MASK_64) == EXP_MASK_64) && ((fvalue & MANT_MASK_64) != 0) && ((fvalue & SIGN_MASK_64) != 0) ) {

	lvalue = SIGN_MASK_32;
    }

    return lvalue;
}

long long Fpu::float128_to_int64_sparc(uint64_t fvalue[2])
{
    long long   llvalue;
    
    llvalue = float128_to_int64(iss_q_to_sf_q(fvalue));

    /* check for negative NaN */

    if ( ((fvalue[0] & EXP_MASK_128H) == EXP_MASK_128H) && 
	 ((fvalue[0] & MANT_MASK_128H) != 0) && 
	 ((fvalue[0] & SIGN_MASK_128H) != 0) )   {

	llvalue = SIGN_MASK_64;
    }
    return llvalue;
}

long Fpu::float128_to_int32_sparc(uint64_t fvalue[2])
{
    long   lvalue;
    
    lvalue = float128_to_int32(iss_q_to_sf_q(fvalue));

    /* check for negative NaN */

    if ( ((fvalue[0] & EXP_MASK_128H) == EXP_MASK_128H) && 
	 ((fvalue[0] & MANT_MASK_128H) != 0) && 
	 ((fvalue[0] & SIGN_MASK_128H) != 0) )   {

	lvalue = SIGN_MASK_32;
    }

    return lvalue;
}

#define OP_REGS_12D_(src1,src2,dest)   src1_type = (src1); src2_type = (src2); dest_type = (dest);


bool Fpu::execute_f3n_instr( InstructionWord &iw ) throw(BasicTrap &)
{
    enum instr_e instr_type = UNKNOWN_INSTR;

    uint64_t		qp_value0[2];
    uint64_t		qp_value1[2];
    uint64_t		dp_value[2];
    uint32_t		sp_value[2];
    uint64_t		value64;
    uint64_t		result64;
    uint32_t		value32;
    uint16_t            svalue16[2];
    uint32_t		result32;
    int64_t		svalue64[2];
    int32_t		svalue32[2];
    uint8_t             svalue8[2];

    uint64_t		dummy_qp[2];
    uint64_t            dummy_dp;

    enum op_reg_type_e	src1_type = UNKNOWN_TYPE;
    enum op_reg_type_e	src2_type = UNKNOWN_TYPE;
    enum op_reg_type_e	dest_type = UNKNOWN_TYPE;
    int  		n;
    int  		index;
    bool  		le;
    bool  		set_ccs;
    uint64_t            ccs_value;
    bool  		xcc_z, xcc_n, xcc_c, xcc_v;
    bool  		icc_z, icc_n, icc_c, icc_v;
    int  		trap_status = NO_TRAP;

    uint64_t		orig_qp_value0[2];
    uint64_t		orig_qp_value1[2];
    uint64_t		orig_dp_value[2];
    uint32_t		orig_sp_value[2];

    fp_op_type          src1_fptype;
    fp_op_type          src2_fptype;
    fp_op_type          dest_fptype;


    /* Exponent calculations */

    int                 Er = 0; // Exponent result
    int                 exp1 = 0; // exponent of rs1
    int                 exp2 = 0; // exponent of rs2


    switch ( iw.opf() ) {
	case OPF_0_0100_0001:   instr_type = FADDS;   break;
	case OPF_0_0100_0010:   instr_type = FADDD;   break;
	case OPF_0_0100_0011:   instr_type = FADDQ;   break;
	case OPF_0_0100_0101:   instr_type = FSUBS;   break;
	case OPF_0_0100_0110:   instr_type = FSUBD;   break;
	case OPF_0_0100_0111:   instr_type = FSUBQ;   break;
	case OPF_0_0100_1001:   instr_type = FMULS;   break;
	case OPF_0_0100_1010:   instr_type = FMULD;   break;
	case OPF_0_0100_1011:   instr_type = FMULQ;   break;
	case OPF_0_0100_1101:   instr_type = FDIVS;   break;
	case OPF_0_0100_1110:   instr_type = FDIVD;   break;
	case OPF_0_0100_1111:   instr_type = FDIVQ;   break;
	case OPF_0_0101_0001:   instr_type = FNADDS;   break;
	case OPF_0_0101_0010:   instr_type = FNADDD;   break;
	case OPF_0_0101_1001:   instr_type = FNMULS;   break;
	case OPF_0_0101_1010:   instr_type = FNMULD;   break;
	case OPF_0_0110_0001:   instr_type = FHADDS;  break;
	case OPF_0_0110_0010:   instr_type = FHADDD;  break;
	case OPF_0_0110_0101:   instr_type = FHSUBS;  break;
	case OPF_0_0110_0110:   instr_type = FHSUBD;  break;
	case OPF_0_0110_1001:   instr_type = FSMULD;  break;
	case OPF_0_0110_1110:   instr_type = FDMULQ;  break;
	case OPF_0_0111_0001:   instr_type = FNHADDS;  break;
	case OPF_0_0111_0010:   instr_type = FNHADDD;  break;
	case OPF_0_0111_1001:   instr_type = FNSMULD;   break;
	default:                instr_type = UNKNOWN_INSTR; break;
    }

    if (instr_type == UNKNOWN_INSTR) {
	return false;
    }

    switch (instr_type) {
	case FADDS:   OP_REGS_12D_( SP_TYPE,  SP_TYPE,  SP_TYPE );   break;
	case FADDD:   OP_REGS_12D_( DP_TYPE,  DP_TYPE,  DP_TYPE );   break;
	case FADDQ:   OP_REGS_12D_( QP_TYPE,  QP_TYPE,  QP_TYPE );   break;
	case FSUBS:   OP_REGS_12D_( SP_TYPE,  SP_TYPE,  SP_TYPE );   break;
	case FSUBD:   OP_REGS_12D_( DP_TYPE,  DP_TYPE,  DP_TYPE );   break;
	case FSUBQ:   OP_REGS_12D_( QP_TYPE,  QP_TYPE,  QP_TYPE );   break;
	case FMULS:   OP_REGS_12D_( SP_TYPE,  SP_TYPE,  SP_TYPE );   break;
	case FMULD:   OP_REGS_12D_( DP_TYPE,  DP_TYPE,  DP_TYPE );   break;
	case FMULQ:   OP_REGS_12D_( QP_TYPE,  QP_TYPE,  QP_TYPE );   break;
	case FDIVS:   OP_REGS_12D_( SP_TYPE,  SP_TYPE,  SP_TYPE );   break;
	case FDIVD:   OP_REGS_12D_( DP_TYPE,  DP_TYPE,  DP_TYPE );   break;
	case FDIVQ:   OP_REGS_12D_( QP_TYPE,  QP_TYPE,  QP_TYPE );   break;
	case FSMULD:  OP_REGS_12D_( SP_TYPE,  SP_TYPE,  DP_TYPE );   break;
	case FDMULQ:  OP_REGS_12D_( DP_TYPE,  DP_TYPE,  QP_TYPE );   break;
	case FNADDS:  OP_REGS_12D_( SP_TYPE,  SP_TYPE,  SP_TYPE );   break;
	case FNADDD:  OP_REGS_12D_( DP_TYPE,  DP_TYPE,  DP_TYPE );   break;
	case FNMULS:  OP_REGS_12D_( SP_TYPE,  SP_TYPE,  SP_TYPE );   break;
	case FNMULD:  OP_REGS_12D_( DP_TYPE,  DP_TYPE,  DP_TYPE );   break;
	case FNSMULD: OP_REGS_12D_( SP_TYPE,  SP_TYPE,  DP_TYPE );   break;
	case FHADDS:  OP_REGS_12D_( SP_TYPE,  SP_TYPE,  SP_TYPE );   break;
	case FHADDD:  OP_REGS_12D_( DP_TYPE,  DP_TYPE,  DP_TYPE );   break;
	case FHSUBS:  OP_REGS_12D_( SP_TYPE,  SP_TYPE,  SP_TYPE );   break;
	case FHSUBD:  OP_REGS_12D_( DP_TYPE,  DP_TYPE,  DP_TYPE );   break;
	case FNHADDS: OP_REGS_12D_( SP_TYPE,  SP_TYPE,  SP_TYPE );   break;
	case FNHADDD: OP_REGS_12D_( DP_TYPE,  DP_TYPE,  DP_TYPE );   break;
	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    if (!throw_fp_exception_other_ && 
	isUnimplementedV9Instruction( iw, instr_type )) {
	// other throw illegal_instruction
	RIESLING_TRAP( V9_Trap::illegal_instruction );
    }

    if ( fpDisabled() ) {
        if ( setFpDirtyBitsWhenFpDisabled() )
	  setFpDirtyBits( iw, dest_type );
	RIESLING_TRAP( FP_DISABLED_TRAP );
    }

    if (throw_fp_exception_other_ && 
	isUnimplementedV9Instruction( iw, instr_type )) {
	// N1 still throws fp_exception_other trap, which has lower priority
	asPtr_->getFsrRegPtr()->setFTT( FTT_UNIMPLEMENTED_FPOP );
	RIESLING_TRAP( FP_EXCEPTION_OTHER_TRAP );
    }

    // Read the source registers

    read_src1_reg( iw, src1_type, orig_qp_value0, &( orig_dp_value[0] ), &( orig_sp_value[0] ), &trap_status );
    read_src2_reg( iw, src2_type, orig_qp_value1, &( orig_dp_value[1] ), &( orig_sp_value[1] ), &trap_status );

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    // Copy the source values into the working variables

    qp_value0[1] = orig_qp_value0[1];
    qp_value0[0] = orig_qp_value0[0];
    qp_value1[1] = orig_qp_value1[1];
    qp_value1[0] = orig_qp_value1[0];

    dp_value[1] = orig_dp_value[1];
    dp_value[0] = orig_dp_value[0];

    sp_value[1] = orig_sp_value[1];
    sp_value[0] = orig_sp_value[0];

    src1_fptype = fpu_optype( src1_type, qp_value0, dp_value[0], sp_value[0] );
    src2_fptype = fpu_optype( src2_type, qp_value1, dp_value[1], sp_value[1] );

    trap_status = fpu_preprocess ( iw, instr_type,
		                   qp_value0, &(dp_value[0]), &(sp_value[0]), src1_fptype,
		                   qp_value1, &(dp_value[1]), &(sp_value[1]), src2_fptype);

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    exp1 = determine_exp( src1_type, qp_value0, &(dp_value[0]), &(sp_value[0]) );
    exp2 = determine_exp( src2_type, qp_value1, &(dp_value[1]), &(sp_value[1]) );

    switch (instr_type) {

	case FADDS:
	    sp_value[0] = float32_add( sp_value[0], sp_value[1], false, false );
	    break;

	case FADDD:
	    dp_value[0] = float64_add( dp_value[0], dp_value[1], false, false );
	    break;

	case FADDQ:
	    sf_q_to_iss_q( ( float128_add( iss_q_to_sf_q( qp_value0 ), iss_q_to_sf_q( qp_value1 ) ) ), qp_value0 );
	    break;

	case FSUBS:
	    sp_value[0] = float32_sub( sp_value[0], sp_value[1], false, false );
	    break;

	case FSUBD:
	    dp_value[0] = float64_sub( dp_value[0], dp_value[1], false, false );
	    break;

	case FSUBQ:
	    sf_q_to_iss_q( ( float128_sub( iss_q_to_sf_q( qp_value0 ), iss_q_to_sf_q( qp_value1 ) ) ) , qp_value0 );
	    break;

	case FMULS:
	    sp_value[0] = float32_mul( sp_value[0], sp_value[1], false );
	    Er = exp1 + exp2 - SP_BIAS;
	    break;

	case FMULD:
	    dp_value[0] = float64_mul( dp_value[0], dp_value[1], false );
	    Er = exp1 + exp2 - DP_BIAS;
	    break;

	case FMULQ:
	    sf_q_to_iss_q( float128_mul( iss_q_to_sf_q( qp_value0 ),
					 iss_q_to_sf_q( qp_value1 ) ),
			   qp_value0 );
	    Er = exp1 + exp2 - QP_BIAS;
	    break;

	case FDIVS:
	    sp_value[0] = float32_div( sp_value[0], sp_value[1] );
	    Er = exp1 - exp2 + SP_BIAS - 1;
	    break;

	case FDIVD:
	    dp_value[0] = float64_div( dp_value[0], dp_value[1] );
	    Er = exp1 - exp2 + DP_BIAS - 1;
	    break;

	case FDIVQ:
	    sf_q_to_iss_q( float128_div( iss_q_to_sf_q( qp_value0 ),
					 iss_q_to_sf_q( qp_value1 ) ),
			   qp_value0 );
	    break;

	case FSMULD:
	    dp_value[0] = float64_mul( float32_to_float64( sp_value[0] ),
				       float32_to_float64( sp_value[1] ),
				       false );
	    break;

	case FDMULQ:
	    sf_q_to_iss_q( float128_mul( float64_to_float128( dp_value[0] ),
					 float64_to_float128( dp_value[1] ) ),
			   qp_value0 );
	    break;

	case FNADDS:
	    sp_value[0] = float32_add( sp_value[0], sp_value[1], true, false );
	    break;

	case FNADDD:
	    dp_value[0] = float64_add( dp_value[0], dp_value[1], true, false );
	    break;

	case FNMULS:
	    sp_value[0] = float32_mul( sp_value[0], sp_value[1], true );
	    Er = exp1 + exp2 - SP_BIAS;
	    break;

	case FNMULD:
	    dp_value[0] = float64_mul( dp_value[0], dp_value[1], true );
	    Er = exp1 + exp2 - DP_BIAS;
	    break;

	case FNSMULD:
	    dp_value[0] = float64_mul( float32_to_float64( sp_value[0] ),
				       float32_to_float64( sp_value[1] ),
				       true );
	    break;

	case FHADDS:
	    sp_value[0] = float32_add( sp_value[0], sp_value[1], false, true );
	    break;

	case FHADDD:
	    dp_value[0] = float64_add( dp_value[0], dp_value[1], false, true );
	    break;

	case FHSUBS:
	    sp_value[0] = float32_sub( sp_value[0], sp_value[1], false, true );
	    break;

	case FHSUBD:
	    dp_value[0] = float64_sub( dp_value[0], dp_value[1], false, true );
	    break;

	case FNHADDS:
	    sp_value[0] = float32_add( sp_value[0], sp_value[1], true, true );
	    break;

	case FNHADDD:
	    dp_value[0] = float64_add( dp_value[0], dp_value[1], true, true );
	    break;

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }   // switch instr_type

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    dest_fptype = fpu_optype( dest_type, qp_value0, dp_value[0], sp_value[0] );

    trap_status = fpu_postprocess( false, iw, instr_type,
				   src1_fptype, src2_fptype, Er, dest_fptype, dest_type,
				   qp_value0, &(dp_value[0]), &(sp_value[0]) ).trap_status;

    if (trap_status == NO_TRAP) {
	switch( instr_type ) {
	    case FADDS:
	    case FADDD:
	    case FADDQ:
	    case FSUBS:
	    case FSUBD:
	    case FSUBQ:
	    case FMULS:
	    case FMULD:
	    case FMULQ:
	    case FDIVS:
	    case FDIVD:
	    case FDIVQ:
	    case FSMULD:
	    case FDMULQ:
	    case FNADDS:
	    case FNADDD:
	    case FNMULS:
	    case FNMULD:
	    case FNSMULD:
	    {
		nan_postprocess( src1_type, src1_fptype, orig_qp_value0, orig_dp_value[0], orig_sp_value[0],
				 src2_type, src2_fptype, orig_qp_value1, orig_dp_value[1], orig_sp_value[1],
				 dest_type, qp_value0, &(dp_value[0]), &(sp_value[0]) );
		break;
	    }

	    default:
		break;
	}
	write_dest_reg( iw, qp_value0, &( dp_value[0] ), &( sp_value[0] ), true, dest_type, &trap_status);
    }

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    INC_PC_AND_NPC();

    return true;
}


bool Fpu::execute_f2c_instr( InstructionWord &iw ) throw(BasicTrap &)
{
    uint64_t	ccs;
    bool  	unconditional_branch;
    bool  	z, n, v, c;
    bool  	e, l, g, u;
    bool  	branch_taken;

    uint32_t    cond, annul_bit;

    int32_t     disp;
    int64_t     delta;
    uint64_t    target_pc, pc_regValue, npc_regValue;

    instr_e     instr_type  = UNKNOWN_INSTR;

    cond = iw.cond();

    switch (cond) {
	case COND_1000:    instr_type = FBA;     break;
	case COND_0000:    instr_type = FBN;     break;
	case COND_0111:    instr_type = FBU;     break;
	case COND_0110:    instr_type = FBG;     break;
	case COND_0101:    instr_type = FBUG;    break;
	case COND_0100:    instr_type = FBL;     break;
	case COND_0011:    instr_type = FBUL;    break;
	case COND_0010:    instr_type = FBLG;    break;
	case COND_0001:    instr_type = FBNE;    break;
	case COND_1001:    instr_type = FBE;     break;
	case COND_1010:    instr_type = FBUE;    break;
	case COND_1011:    instr_type = FBGE;    break;
	case COND_1100:    instr_type = FBUGE;   break;
	case COND_1101:    instr_type = FBLE;    break;
	case COND_1110:    instr_type = FBULE;   break;
	case COND_1111:    instr_type = FBO;     break;

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    if ( fpDisabled() ) {
        RIESLING_TRAP( FP_DISABLED_TRAP );
    }

    unconditional_branch = ( ( instr_type == FBA ) || ( instr_type == FBN ) );

    if ( !unconditional_branch ) {
	access_decoded_fccs( 0, &e, &l, &g, &u, READ_ACCESS );
    }

    switch ( instr_type ) {
	/**********************************************************************
	 *	'Branch on fcc0' instructions . . .
	 *********************************************************************/
	case FBNE:      branch_taken = l | g | u;	break;
	case FBE:       branch_taken = e;		break;
	case FBN:	branch_taken = false;		break;
	case FBLG:	branch_taken = l | g;		break;
	case FBUL:	branch_taken = l | u;		break;
	case FBL:	branch_taken = l;		break;
	case FBUG:	branch_taken = u | g;		break;
	case FBG:	branch_taken = g;		break;
	case FBU:	branch_taken = u;		break;
	case FBA:	branch_taken = true;		break;
	case FBUE:	branch_taken = e | u;		break;
	case FBGE:	branch_taken = e | g;		break;
	case FBUGE:	branch_taken = e | g | u;	break;
	case FBLE:	branch_taken = e | l;		break;
	case FBULE:	branch_taken = e | l | u;	break;
	case FBO:	branch_taken = e | l | g;	break;

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    // If the branch is taken...

    annul_bit = iw.a();

    if ( branch_taken ) {

      if (!pstate_tct_enabled_)
      {
	disp      = iw.disp22();
	delta     = ((disp << 10) >> 8);
	target_pc = asPtr_->getPc() + delta;

	if ( unconditional_branch && annul_bit ) {
	    asPtr_->setAnnulled( annul_bit );
	} else {
	    asPtr_->setAnnulled( false );
	}
        asPtr_->setPc(asPtr_->getNpc());
        asPtr_->setNpc(target_pc);
      }
      pstate_tct_launch_ = pstate_tct_enabled_;
    } else {
      pstate_tct_launch_ = false;
      
      target_pc = asPtr_->getNpc() + 4;
      if ( annul_bit ) {
        asPtr_->setAnnulled( annul_bit );
      }
      asPtr_->setPc(asPtr_->getNpc());
      asPtr_->setNpc(target_pc);
    }


    return true;
}


bool Fpu::execute_f2d_instr( InstructionWord &iw ) throw(BasicTrap &)
{
    uint64_t	ccs;
    bool  	unconditional_branch;
    bool  	z, n, v, c;
    bool  	e, l, g, u;
    bool  	branch_taken;

    uint32_t    cond, annul_bit;

    int32_t     disp;
    int64_t     delta;
    uint64_t    target_pc, pc_regValue, npc_regValue;
    int         fcc_num;

    instr_e     instr_type  = UNKNOWN_INSTR;

    cond = iw.cond();

    switch (cond) {
	case COND_1000:    instr_type = FBPA;     break;
	case COND_0000:    instr_type = FBPN;     break;
	case COND_0111:    instr_type = FBPU;     break;
	case COND_0110:    instr_type = FBPG;     break;
	case COND_0101:    instr_type = FBPUG;    break;
	case COND_0100:    instr_type = FBPL;     break;
	case COND_0011:    instr_type = FBPUL;    break;
	case COND_0010:    instr_type = FBPLG;    break;
	case COND_0001:    instr_type = FBPNE;    break;
	case COND_1001:    instr_type = FBPE;     break;
	case COND_1010:    instr_type = FBPUE;    break;
	case COND_1011:    instr_type = FBPGE;    break;
	case COND_1100:    instr_type = FBPUGE;   break;
	case COND_1101:    instr_type = FBPLE;    break;
	case COND_1110:    instr_type = FBPULE;   break;
	case COND_1111:    instr_type = FBPO;     break;

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    if ( fpDisabled() ) {
        RIESLING_TRAP( FP_DISABLED_TRAP );
    }

    unconditional_branch = ( ( instr_type == FBPA ) || ( instr_type == FBPN ) );

    if ( !unconditional_branch ) {
	fcc_num  =  iw.cc0();
	fcc_num |= (iw.cc1() << 1);
	access_decoded_fccs( fcc_num, &e, &l, &g, &u, READ_ACCESS );
    }

    switch ( instr_type ) {
	/**********************************************************************
	 *	'Branch on fcc0' instructions . . .
	 *********************************************************************/
	case FBPNE:     branch_taken = l | g | u;	break;
	case FBPE:      branch_taken = e;		break;
	case FBPN:	branch_taken = false;		break;
	case FBPLG:	branch_taken = l | g;		break;
	case FBPUL:	branch_taken = l | u;		break;
	case FBPL:	branch_taken = l;		break;
	case FBPUG:	branch_taken = u | g;		break;
	case FBPG:	branch_taken = g;		break;
	case FBPU:	branch_taken = u;		break;
	case FBPA:	branch_taken = true;		break;
	case FBPUE:	branch_taken = e | u;		break;
	case FBPGE:	branch_taken = e | g;		break;
	case FBPUGE:	branch_taken = e | g | u;	break;
	case FBPLE:	branch_taken = e | l;		break;
	case FBPULE:	branch_taken = e | l | u;	break;
	case FBPO:	branch_taken = e | l | g;	break;

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    // If the branch is taken...

    annul_bit = iw.a();

    if ( branch_taken ) {
      if (!pstate_tct_enabled_)
      {
	disp      = iw.disp19();
	delta     = ((disp << 13) >> 11);
	target_pc = asPtr_->getPc() + delta;

	if ( unconditional_branch && annul_bit ) {
	    asPtr_->setAnnulled( annul_bit );
	} else {
	    asPtr_->setAnnulled( false );
	}
        asPtr_->setPc(asPtr_->getNpc());
        asPtr_->setNpc(target_pc);
      }
      pstate_tct_launch_ = pstate_tct_enabled_;
    } else {
      pstate_tct_launch_ = false;
      target_pc = asPtr_->getNpc() + 4;
      if ( annul_bit ) {
        asPtr_->setAnnulled( annul_bit );
      }
      asPtr_->setPc(asPtr_->getNpc());
      asPtr_->setNpc(target_pc);
    }

    return true;
}


bool
Fpu::execute_f3l_instr( InstructionWord &iw ) throw(BasicTrap &)
{
    /* Source values */
    uint64_t		orig_qp_value[2];
    uint64_t		orig_dp_value[2];
    uint32_t		orig_sp_value;

    /* Working values (initial & final) */
    uint64_t		qp_value[2];
    uint64_t		dp_value;
    uint32_t		sp_value;

    /* Intermediate values */
    uint64_t		value64;
    uint64_t		result64;
    int64_t 		svalue64;
    uint32_t		value32;

    /* Number type */
    enum op_reg_type_e	src2_type = UNKNOWN_TYPE;
    enum op_reg_type_e	dest_type = UNKNOWN_TYPE;

    int  		n;  // counter value

    int  		trap_status = NO_TRAP; // return value

    fp_op_type          src2_fptype; // floating-point type
    fp_op_type          dest_fptype;
    instr_e             instr_type = UNKNOWN_INSTR;

    /* Place holders since we are only dealing with single operand instructions */
    uint64_t qp_dummy[2];
    uint64_t dp_dummy;
    uint32_t sp_dummy;

    /* Exponent calculations */
    int              Er = 0; // Exponent result
    int              exp2 = 0; // exponent of rs2

    switch (iw.opf()) {
	case OPF_0_0000_0001:    instr_type = FMOVS;    break;
	case OPF_0_0000_0010:    instr_type = FMOVD;    break;
	case OPF_0_0000_0011:    instr_type = FMOVQ;    break;
	case OPF_0_0000_0101:    instr_type = FNEGS;    break;
	case OPF_0_0000_0110:    instr_type = FNEGD;    break;
	case OPF_0_0000_0111:    instr_type = FNEGQ;    break;
	case OPF_0_0000_1001:    instr_type = FABSS;    break;
	case OPF_0_0000_1010:    instr_type = FABSD;    break;
	case OPF_0_0000_1011:    instr_type = FABSQ;    break;
	case OPF_0_0010_1001:    instr_type = FSQRTS;   break;
	case OPF_0_0010_1010:    instr_type = FSQRTD;   break;
	case OPF_0_0010_1011:    instr_type = FSQRTQ;   break;
	case OPF_0_1000_0001:    instr_type = FSTOX;    break;
	case OPF_0_1000_0010:    instr_type = FDTOX;    break;
	case OPF_0_1000_0011:    instr_type = FQTOX;    break;
	case OPF_0_1000_0100:    instr_type = FXTOS;    break;
	case OPF_0_1000_1000:    instr_type = FXTOD;    break;
	case OPF_0_1000_1100:    instr_type = FXTOQ;    break;
	case OPF_0_1100_0100:    instr_type = FITOS;    break;
	case OPF_0_1100_0110:    instr_type = FDTOS;    break;
	case OPF_0_1100_1110:    instr_type = FDTOQ;    break;
	case OPF_0_1100_0111:    instr_type = FQTOS;    break;
	case OPF_0_1100_1011:    instr_type = FQTOD;    break;
	case OPF_0_1100_1000:    instr_type = FITOD;    break;
	case OPF_0_1100_1001:    instr_type = FSTOD;    break;
	case OPF_0_1100_1100:    instr_type = FITOQ;    break;
	case OPF_0_1100_1101:    instr_type = FSTOQ;    break;
	case OPF_0_1101_0001:    instr_type = FSTOI;    break;
	case OPF_0_1101_0010:    instr_type = FDTOI;    break;
	case OPF_0_1101_0011:    instr_type = FQTOI;    break;
	default:                 instr_type = UNKNOWN_INSTR;  break;
    }

    if (instr_type == UNKNOWN_INSTR)
	return false;


    switch ( instr_type ) {
	case FMOVS:    src2_type = SP_TYPE;    dest_type = SP_TYPE;    break;
	case FMOVD:    src2_type = DP_TYPE;    dest_type = DP_TYPE;    break;
	case FMOVQ:    src2_type = QP_TYPE;    dest_type = QP_TYPE;    break;
	case FNEGS:    src2_type = SP_TYPE;    dest_type = SP_TYPE;    break;
	case FNEGD:    src2_type = DP_TYPE;    dest_type = DP_TYPE;    break;
	case FNEGQ:    src2_type = QP_TYPE;    dest_type = QP_TYPE;    break;
	case FABSS:    src2_type = SP_TYPE;    dest_type = SP_TYPE;    break;
	case FABSD:    src2_type = DP_TYPE;    dest_type = DP_TYPE;    break;
	case FABSQ:    src2_type = QP_TYPE;    dest_type = QP_TYPE;    break;
	case FSQRTS:   src2_type = SP_TYPE;    dest_type = SP_TYPE;    break;
	case FSQRTD:   src2_type = DP_TYPE;    dest_type = DP_TYPE;    break;
	case FSQRTQ:   src2_type = QP_TYPE;    dest_type = QP_TYPE;    break;
	case FSTOX:    src2_type = SP_TYPE;    dest_type = DP_TYPE;    break;
	case FDTOX:    src2_type = DP_TYPE;    dest_type = DP_TYPE;    break;
	case FQTOX:    src2_type = QP_TYPE;    dest_type = DP_TYPE;    break;
	case FXTOS:    src2_type = DP_TYPE;    dest_type = SP_TYPE;    break;
	case FXTOD:    src2_type = DP_TYPE;    dest_type = DP_TYPE;    break;
	case FXTOQ:    src2_type = DP_TYPE;    dest_type = QP_TYPE;    break;
	case FSTOD:    src2_type = SP_TYPE;    dest_type = DP_TYPE;    break;
	case FSTOQ:    src2_type = SP_TYPE;    dest_type = QP_TYPE;    break;
	case FDTOS:    src2_type = DP_TYPE;    dest_type = SP_TYPE;    break;
	case FDTOQ:    src2_type = DP_TYPE;    dest_type = QP_TYPE;    break;
	case FQTOS:    src2_type = QP_TYPE;    dest_type = SP_TYPE;    break;
	case FQTOD:    src2_type = QP_TYPE;    dest_type = DP_TYPE;    break;
	case FITOS:    src2_type = SP_TYPE;    dest_type = SP_TYPE;    break;
	case FITOD:    src2_type = SP_TYPE;    dest_type = DP_TYPE;    break;
	case FITOQ:    src2_type = SP_TYPE;    dest_type = QP_TYPE;    break;
	case FSTOI:    src2_type = SP_TYPE;    dest_type = SP_TYPE;    break;
	case FDTOI:    src2_type = DP_TYPE;    dest_type = SP_TYPE;    break;
	case FQTOI:    src2_type = QP_TYPE;    dest_type = SP_TYPE;    break;
	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    if ( !throw_fp_exception_other_ && ( 
	 isUnimplementedV9Instruction( iw, instr_type) || iw.fguNonZeroReservedBits())) {
	// other throw illegal_instruction
        RIESLING_TRAP( V9_Trap::illegal_instruction );
    }

    if ( fpDisabled() ) {
	if ( setFpDirtyBitsWhenFpDisabled() ) {
		setFpDirtyBits( iw, dest_type );
	}
	RIESLING_TRAP( FP_DISABLED_TRAP );
    }

    if (throw_fp_exception_other_ && 
	(isUnimplementedV9Instruction( iw, instr_type ) || iw.fguNonZeroReservedBits())) {
	// N1 still throws pf_exception_other trap, which has lower priority
	asPtr_->getFsrRegPtr()->setFTT( FTT_UNIMPLEMENTED_FPOP );
	RIESLING_TRAP( FP_EXCEPTION_OTHER_TRAP );
    }

    read_src2_reg( iw, src2_type, orig_qp_value, &(orig_dp_value[1]), &orig_sp_value, &trap_status );

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    orig_dp_value[0] = 0;

    qp_value[1] = orig_qp_value[1];
    qp_value[0] = orig_qp_value[0];
    dp_value    = orig_dp_value[1];
    sp_value    = orig_sp_value;

    src2_fptype = fpu_optype( src2_type, qp_value, dp_value, sp_value );

    trap_status = fpu_preprocess( iw, instr_type,
                                  qp_dummy, &dp_dummy, &sp_dummy, FP_OP_NONE,
                                  qp_value, &dp_value, &sp_value, src2_fptype);

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    exp2 = determine_exp( src2_type, qp_value, &dp_value, &sp_value );

    switch ( instr_type ) {

	case FMOVS:
	case FMOVD:
	case FMOVQ:
	   break;

	case FNEGS:
	   sp_value ^= WORD_SIGN_MASK;
	   break;

	case FNEGD:
	   dp_value ^= DWORD_SIGN_MASK;
	   break;

	case FNEGQ:
	   qp_value[0] ^= DWORD_SIGN_MASK;
	   break;

	case FABSS:
	   sp_value &= ( ~ WORD_SIGN_MASK );
	   break;

	case FABSD:
	   dp_value &= ( ~ DWORD_SIGN_MASK );
	   break;

	case FABSQ:
	   qp_value[0] &= ( ~ DWORD_SIGN_MASK );
	   break;

	case FSQRTS:
#ifdef RS_MPSAS_COMPATIBLE
           if (( sp_value & SIGN_MASK_32 ) == SIGN_MASK_32) {
	       Er = 1;
	   } else {
	       Er = 0;
	   }
#endif /* RS_MPSAS_COMPATIBLE */
	   sp_value = float32_sqrt( sp_value );
	   break;

	case FSQRTD:
#ifdef RS_MPSAS_COMPATIBLE
           if (( dp_value & SIGN_MASK_64 ) == SIGN_MASK_64) {
	       Er = 1;
	   } else {
	       Er = 0;
	   }
#endif /* RS_MPSAS_COMPATIBLE */
	   dp_value = float64_sqrt( dp_value );
	   break;

	case FSQRTQ:
	   sf_q_to_iss_q( float128_sqrt( iss_q_to_sf_q( qp_value ) ),  qp_value );
	   break;

	case FSTOX:
	   dp_value = float32_to_int64_sparc( sp_value );
	   break;

	case FDTOX:
	   dp_value = float64_to_int64_sparc( dp_value );
	   break;

	case FQTOX:
	   dp_value = float128_to_int64_sparc( qp_value );
	   break;

	case FXTOS:
	   sp_value = int64_to_float32( dp_value );
	   break;

	case FXTOD:
	   dp_value = int64_to_float64( dp_value );
	   break;

	case FXTOQ:
	   sf_q_to_iss_q( int64_to_float128( dp_value ), qp_value );
	   break;

	case FSTOD:
	   dp_value = float32_to_float64( sp_value );
	   break;

	case FSTOQ:
	   sf_q_to_iss_q( float32_to_float128( sp_value ), qp_value );
	   break;

	case FDTOS:
	   sp_value = float64_to_float32( dp_value );
	   Er = exp2 - DP_BIAS + SP_BIAS;
	   break;

	case FDTOQ:
	   sf_q_to_iss_q( float64_to_float128( dp_value ), qp_value );
	   break;

	case FQTOS:
	   sp_value = float128_to_float32( iss_q_to_sf_q( qp_value ) );
	   break;

	case FQTOD:
	   dp_value = float128_to_float64( iss_q_to_sf_q( qp_value ) );
	   Er = exp2 - QP_BIAS + DP_BIAS;
	   break;

	case FITOS:
	   sp_value = int32_to_float32( sp_value );
	   break;

	case FITOD:
	   dp_value = int32_to_float64( sp_value );
	   break;

	case FITOQ:
	   sf_q_to_iss_q( int32_to_float128( sp_value ), qp_value );
	   break;

	case FSTOI:
	   sp_value = float32_to_int32_sparc( sp_value );
	   break;

	case FDTOI:
	   sp_value = float64_to_int32_sparc( dp_value );
	   break;

	case FQTOI:
	   sp_value = float128_to_int32_sparc( qp_value );
	   break;

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    dest_fptype = fpu_optype( dest_type, qp_value, dp_value, sp_value );

    trap_status = (fpu_postprocess( false, iw, instr_type,
				    FP_OP_NONE, src2_fptype, Er, dest_fptype, dest_type,
				    qp_value, &dp_value, &sp_value)).trap_status;

    if ( trap_status == NO_TRAP ) {
	write_dest_reg( iw, qp_value, &dp_value, &sp_value, true, dest_type, &trap_status);
    } 
    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    INC_PC_AND_NPC();

    return true;
}


bool Fpu::execute_f3m_instr( InstructionWord &iw ) throw(BasicTrap &)
{
    //Source values
    uint64_t    qp_value0[2];
    uint64_t    qp_value1[2];
    uint64_t    dp_value[2];
    uint32_t    sp_value[2];

    uint64_t        fccx;
    enum op_reg_type_e    srcx_type = UNKNOWN_TYPE;
    fp_op_type            src1_fptype;
    fp_op_type            src2_fptype;

    uint64_t             qp_dummy[2];
    uint64_t             dp_dummy;
    uint32_t             sp_dummy;


    bool    e, l, g, u;
    int     fcc_num;

    instr_e    instr_type  = UNKNOWN_INSTR;
    int        trap_status = NO_TRAP;

    switch (iw.opf()) {
	case OPF_0_0101_0001:    instr_type = FCMPS;    break;
	case OPF_0_0101_0010:    instr_type = FCMPD;    break;
	case OPF_0_0101_0011:    instr_type = FCMPQ;    break;
	case OPF_0_0101_0101:    instr_type = FCMPES;   break;
	case OPF_0_0101_0110:    instr_type = FCMPED;   break;
	case OPF_0_0101_0111:    instr_type = FCMPEQ;   break;
	default:                 instr_type = UNKNOWN_INSTR;  break;
    }

    if (instr_type == UNKNOWN_INSTR)
	return false;

//     if (isUnimplementedV9Instruction(iw, instr_type) ||
// 	(iw.get(29,27) != 0))
//     {
// 	RIESLING_TRAP( V9_Trap::illegal_instruction );
//     }

    if ( (!throw_fp_exception_other_ && 
	 (isUnimplementedV9Instruction( iw, instr_type ) || iw.fguNonZeroReservedBits()))) {
	// other throw illegal_instruction
        RIESLING_TRAP( V9_Trap::illegal_instruction );
    }

    if ( fpDisabled() ) {
	RIESLING_TRAP( FP_DISABLED_TRAP );
    }

    if (throw_fp_exception_other_ && 
	(isUnimplementedV9Instruction( iw, instr_type ) || iw.fguNonZeroReservedBits() || (iw.get(29,27) != 0))) {
	// N1 still throws pf_exception_other trap, which has lower priority
	asPtr_->getFsrRegPtr()->setFTT( FTT_UNIMPLEMENTED_FPOP );
	RIESLING_TRAP( FP_EXCEPTION_OTHER_TRAP );
    }

    switch ( instr_type ) {
	case FCMPS:    srcx_type = SP_TYPE;    break;
	case FCMPES:   srcx_type = SP_TYPE;    break;
	case FCMPD:    srcx_type = DP_TYPE;    break;
	case FCMPED:   srcx_type = DP_TYPE;    break;
	case FCMPQ:    srcx_type = QP_TYPE;    break;
	case FCMPEQ:   srcx_type = QP_TYPE;    break;
	case FLCMPS:   srcx_type = SP_TYPE;    break;
	case FLCMPD:   srcx_type = DP_TYPE;    break;
	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    read_src1_reg ( iw, srcx_type, qp_value0, &( dp_value[0] ), &( sp_value[0] ), &trap_status);
    read_src2_reg ( iw, srcx_type, qp_value1, &( dp_value[1] ), &( sp_value[1] ), &trap_status);

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    src1_fptype = fpu_optype( srcx_type, qp_value0, dp_value[0], sp_value[0] );
    src2_fptype = fpu_optype( srcx_type, qp_value1, dp_value[1], sp_value[1] );

    trap_status = fpu_preprocess ( iw, instr_type,
		                   qp_value0, &dp_value[0], &sp_value[0], src1_fptype,
		                   qp_value1, &dp_value[1], &sp_value[1], src2_fptype );

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }


    switch ( instr_type ) {
	case FCMPS:
	    e = float32_eq( sp_value[0], sp_value[1] );
	    l = float32_lt_quiet( sp_value[0], sp_value[1] );
	    g = float32_lt_quiet( sp_value[1], sp_value[0] ) && ( ! e );
	    break;

	case FCMPES:
	    e = float32_eq_signaling( sp_value[0], sp_value[1] );
	    l = float32_lt( sp_value[0], sp_value[1] );
	    g = float32_lt( sp_value[1], sp_value[0] ) && ( ! e );
	    break;

	case FCMPD:
	    e = float64_eq( dp_value[0], dp_value[1] );
	    l = float64_lt_quiet( dp_value[0], dp_value[1] );
	    g = float64_lt_quiet( dp_value[1], dp_value[0] ) && ( ! e );
	    break;

	case FCMPED:
	    e = float64_eq_signaling( dp_value[0], dp_value[1] );
	    l = float64_lt( dp_value[0], dp_value[1] );
	    g = float64_lt( dp_value[1], dp_value[0] ) && ( ! e );
	    break;

	case FCMPQ:
	    e = float128_eq( iss_q_to_sf_q ( qp_value0 ), iss_q_to_sf_q ( qp_value1 ) );
	    l = float128_lt_quiet( iss_q_to_sf_q( qp_value0 ), iss_q_to_sf_q( qp_value1 ) );
	    g = float128_lt_quiet( iss_q_to_sf_q( qp_value1 ), iss_q_to_sf_q( qp_value0 ) ) && ( ! e );
	    break;

	case FCMPEQ:
	    e = float128_eq_signaling( iss_q_to_sf_q( qp_value0 ), iss_q_to_sf_q( qp_value1 ) );
	    l = float128_lt( iss_q_to_sf_q( qp_value0 ), iss_q_to_sf_q( qp_value1 ) );
	    g = float128_lt( iss_q_to_sf_q( qp_value1 ), iss_q_to_sf_q ( qp_value0 ) ) && ( ! e );
	    break;

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    trap_status = (fpu_postprocess( false, iw, instr_type,
				    src1_fptype, src2_fptype, 0, FP_OP_NONE, srcx_type,
				    qp_dummy, &dp_dummy, &sp_dummy )).trap_status;

    if ( trap_status == NO_TRAP ) {

	u = ( ! ( e || l || g ) );
	fcc_num  =  iw.cc0();
	fcc_num |= (iw.cc1() << 1);
	access_decoded_fccs( fcc_num, &e, &l, &g, &u, WRITE_ACCESS );

	asPtr_->setPc(asPtr_->getNpc());
	asPtr_->setNpc(asPtr_->getNpc() + 4);

    } else {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    return true;
}

bool Fpu::execute_f4b_instr( InstructionWord &iw ) throw(BasicTrap &)
{
    uint64_t		src2;
    uint32_t		fcc_num;
    bool  		dont_read_ccs;
    bool  		z, n, v, c;
    bool  		e, l, g, u;
    bool  		move_reg;

    instr_e    instr_type  = UNKNOWN_INSTR;

    switch ( iw.cond() ) {
	case COND_0001:    	instr_type = MOVFNE;     break;
	case COND_1001:    	instr_type = MOVFE;      break;
	case COND_0000:    	instr_type = MOVFN;      break;
	case COND_0010:    	instr_type = MOVFLG;     break;
	case COND_0011:    	instr_type = MOVFUL;     break;
	case COND_0100:    	instr_type = MOVFL;      break;
	case COND_0101:    	instr_type = MOVFUG;     break;
	case COND_0110:    	instr_type = MOVFG;      break;
	case COND_0111:    	instr_type = MOVFU;      break;
	case COND_1000:    	instr_type = MOVFA;      break;
	case COND_1010:    	instr_type = MOVFUE;     break;
	case COND_1011:    	instr_type = MOVFGE;     break;
	case COND_1100:    	instr_type = MOVFUGE;    break;
	case COND_1101:    	instr_type = MOVFLE;     break;
	case COND_1110:    	instr_type = MOVFULE;    break;
	case COND_1111:    	instr_type = MOVFO;      break;

	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    fcc_num  =  iw.cc0();
    fcc_num |= (iw.cc1() << 1);
    fcc_num |= (iw.cc2() << 2);

    if ( (fcc_num == 0x4) || (fcc_num == 0x6) ) {
	RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
    }

    if (!throw_fp_exception_other_ && 
	isUnimplementedV9Instruction( iw, instr_type )) {
	// other throw illegal_instruction
	RIESLING_TRAP( V9_Trap::illegal_instruction );
    }

    if ( fpDisabled() ) {
	RIESLING_TRAP( FP_DISABLED_TRAP );
    }

    if (throw_fp_exception_other_ && 
	isUnimplementedV9Instruction( iw, instr_type )) {
	// N1 still throws pf_exception_other trap, which has lower priority
	asPtr_->getFsrRegPtr()->setFTT( FTT_UNIMPLEMENTED_FPOP );
	RIESLING_TRAP( FP_EXCEPTION_OTHER_TRAP );
    }

    dont_read_ccs = ( ( instr_type == MOVFA ) || ( instr_type == MOVFN ) );

    if ( iw.i() ) {
	src2 = iw.simm11();
    } else {
	src2 = asPtr_->getRegisterFilePtr()->get( iw.rs2() );
    }

    if ( ! dont_read_ccs ) {

	access_decoded_fccs( fcc_num, &e, &l, &g, &u, READ_ACCESS );
    }

    switch ( instr_type ) {
	case MOVFNE:    move_reg = l | g | u;	break;
	case MOVFE:     move_reg = e;		break;
	case MOVFN:	move_reg = false;	break;
	case MOVFLG:	move_reg = l | g;	break;
	case MOVFUL:	move_reg = l | u;	break;
	case MOVFL:	move_reg = l;		break;
	case MOVFUG:	move_reg = g | u;	break;
	case MOVFG:	move_reg = g;		break;
	case MOVFU:	move_reg = u;		break;
	case MOVFA:	move_reg = true;	break;
	case MOVFUE:	move_reg = e | u;	break;
	case MOVFGE:	move_reg = e | g;	break;
	case MOVFUGE:	move_reg = e | g | u;	break;
	case MOVFLE:	move_reg = e | l;	break;
	case MOVFULE:	move_reg = e | l | u;	break;
	case MOVFO:	move_reg = e | l | g;	break;
    }

    if (move_reg) {
	asPtr_->getRegisterFilePtr()->set( iw.rd(), src2 );
    }

    INC_PC_AND_NPC();

    return true;
}

bool Fpu::execute_f4c_instr( InstructionWord &iw ) throw(BasicTrap &)
{
    uint64_t        src1;
    uint64_t        dp_value;
    uint64_t        qp_value[2];
    uint32_t        sp_value;
    enum op_reg_type_e    fp_type;
    bool          z, n;
    bool          move_reg;

    V9_FsrReg   *fsrPtr = asPtr_->getFsrRegPtr();

    instr_e    instr_type  = UNKNOWN_INSTR;
    int        trap_status = NO_TRAP;
    bool       illegal_rcond = false;


    switch (iw.opf() & 0x1F) {

	case OPF_LOW_0_0101: 
	{
	    switch (iw.rcond()) {
		case RCOND_001:    instr_type = FMOVRSE;    break;
		case RCOND_010:    instr_type = FMOVRSLEZ;  break;
		case RCOND_011:    instr_type = FMOVRSLZ;   break;
		case RCOND_101:    instr_type = FMOVRSNE;   break;
		case RCOND_110:    instr_type = FMOVRSGZ;   break;
		case RCOND_111:    instr_type = FMOVRSGEZ;  break;
		default:           instr_type = UNKNOWN_INSTR;    illegal_rcond = true;   break;
	    }
	    break;
	}

	case OPF_LOW_0_0110: 
	{
	    switch (iw.rcond()) {
		case RCOND_001:    instr_type = FMOVRDE;    break;
		case RCOND_010:    instr_type = FMOVRDLEZ;  break;
		case RCOND_011:    instr_type = FMOVRDLZ;   break;
		case RCOND_101:    instr_type = FMOVRDNE;   break;
		case RCOND_110:    instr_type = FMOVRDGZ;   break;
		case RCOND_111:    instr_type = FMOVRDGEZ;  break;
		default:           instr_type = UNKNOWN_INSTR;    illegal_rcond = true;   break;
	    }
	    break;
	}

	case OPF_LOW_0_0111: 
	{
	    switch (iw.rcond()) {
		case RCOND_001:    instr_type = FMOVRQE;    break;
		case RCOND_010:    instr_type = FMOVRQLEZ;  break;
		case RCOND_011:    instr_type = FMOVRQLZ;   break;
		case RCOND_101:    instr_type = FMOVRQNE;   break;
		case RCOND_110:    instr_type = FMOVRQGZ;   break;
		case RCOND_111:    instr_type = FMOVRQGEZ;  break;
		default:           instr_type = UNKNOWN_INSTR;    illegal_rcond = true;   break;
	    }
	    break;
	}
    }

//     if (isUnimplementedV9Instruction(iw, instr_type) ||
// 	illegal_rcond ||
// 	(iw.get( 13, 13 ) != 0))
//     {
//         RIESLING_TRAP( V9_Trap::illegal_instruction );
//     }

    if (!throw_fp_exception_other_ && 
	 (isUnimplementedV9Instruction( iw, instr_type ) || iw.fguNonZeroReservedBits())){
	// other throw illegal_instruction
        RIESLING_TRAP( V9_Trap::illegal_instruction );
    }

    if ( fpDisabled() ) {
	RIESLING_TRAP( FP_DISABLED_TRAP );
    }

    if (throw_fp_exception_other_ && 
	(isUnimplementedV9Instruction( iw, instr_type ) || iw.fguNonZeroReservedBits() || (iw.get( 13, 13 ) != 0) || illegal_rcond )) {
	// N1 still throws fp_exception_other trap, which has lower priority
	asPtr_->getFsrRegPtr()->setFTT( FTT_UNIMPLEMENTED_FPOP );
	RIESLING_TRAP( FP_EXCEPTION_OTHER_TRAP );
    }

    if (instr_type == UNKNOWN_INSTR)
	return false;

    src1 = asPtr_->getRegisterFilePtr()->get(iw.rs1());

    z = ( src1 == 0 );
    n = ( ( src1 & DWORD_SIGN_MASK ) != 0 );

    switch ( instr_type ) {
	/***********************************************************************
	*    FMOVRSxxx instructions . . .
	**********************************************************************/
	case FMOVRSE:    move_reg = z;              fp_type = SP_TYPE;    break;
	case FMOVRSNE:   move_reg = ! z;            fp_type = SP_TYPE;    break;
	case FMOVRSLEZ:  move_reg = n | z;          fp_type = SP_TYPE;    break;
	case FMOVRSLZ:   move_reg = n;              fp_type = SP_TYPE;    break;
	case FMOVRSGZ:   move_reg = ! ( n | z );    fp_type = SP_TYPE;    break;
	case FMOVRSGEZ:  move_reg = ! n;            fp_type = SP_TYPE;    break;
	/***********************************************************************
	*    FMOVRDxxx instructions . . .
	**********************************************************************/
	case FMOVRDE:    move_reg = z;              fp_type = DP_TYPE;    break;
	case FMOVRDNE:   move_reg = ! z;            fp_type = DP_TYPE;    break;
	case FMOVRDLEZ:  move_reg = n | z;          fp_type = DP_TYPE;    break;
	case FMOVRDLZ:   move_reg = n;              fp_type = DP_TYPE;    break;
	case FMOVRDGZ:   move_reg = ! ( n | z );    fp_type = DP_TYPE;    break;
	case FMOVRDGEZ:  move_reg = ! n;            fp_type = DP_TYPE;    break;
	/***********************************************************************
	*    FMOVRQxxx instructions . . .
	**********************************************************************/
	case FMOVRQE:    move_reg = z;              fp_type = QP_TYPE;    break;
	case FMOVRQNE:   move_reg = ! z;            fp_type = QP_TYPE;    break;
	case FMOVRQLEZ:  move_reg = n | z;          fp_type = QP_TYPE;    break;
	case FMOVRQLZ:   move_reg = n;              fp_type = QP_TYPE;    break;
	case FMOVRQGZ:   move_reg = ! ( n | z );    fp_type = QP_TYPE;    break;
	case FMOVRQGEZ:  move_reg = ! n;            fp_type = QP_TYPE;    break;
	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }

    if ( fpDisabled() ) {
        if ( setFpDirtyBitsWhenFpDisabled() )
	  setFpDirtyBits( iw, fp_type );
	RIESLING_TRAP( FP_DISABLED_TRAP );
    }

    read_src2_reg( iw, fp_type, qp_value, &dp_value, &sp_value, &trap_status);

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    fsrPtr->setCEXC(0);

    if (move_reg) {
	write_dest_reg( iw, qp_value, &dp_value, &sp_value, move_reg, fp_type, &trap_status);

	if ( trap_status != NO_TRAP ) {
	    BasicTrap trapObject( trap_status );
	    throw trapObject;
	}
    }

    fsrPtr->setFTT(0);

    INC_PC_AND_NPC();

    return true;
}


bool Fpu::execute_f4d_instr( InstructionWord &iw ) throw(BasicTrap &)
{
    uint64_t    qp_value[2];
    uint64_t    dp_value;
    uint32_t    sp_value;
    enum op_reg_type_e    fp_type;
    enum op_reg_type_e    dest_type = UNKNOWN_TYPE;
    bool    dont_read_ccs;
    bool    z, n, v, c;
    bool    e, l, g, u;
    bool    move_reg;

    uint64_t qp_dummy[2];
    uint64_t dp_dummy;
    uint32_t sp_dummy;

    int    cc_index;

    instr_e    instr_type  = UNKNOWN_INSTR;
    int        trap_status = NO_TRAP;


    switch (iw.opf() & ~OPF_0_XX00_0000)  {

	case OPF_0_XX00_0001: 
	{
	    dest_type = SP_TYPE;
	    switch (iw.cond()) {
		case COND_1000:    instr_type = FMOVFSA;      break;
		case COND_0000:    instr_type = FMOVFSN;      break;
		case COND_0111:    instr_type = FMOVFSU;      break;
		case COND_0110:    instr_type = FMOVFSG;      break;
		case COND_0101:    instr_type = FMOVFSUG;     break;
		case COND_0100:    instr_type = FMOVFSL;      break;
		case COND_0011:    instr_type = FMOVFSUL;     break;
		case COND_0010:    instr_type = FMOVFSLG;     break;
		case COND_0001:    instr_type = FMOVFSNE;     break;
		case COND_1001:    instr_type = FMOVFSE;      break;
		case COND_1010:    instr_type = FMOVFSUE;     break;
		case COND_1011:    instr_type = FMOVFSGE;     break;
		case COND_1100:    instr_type = FMOVFSUGE;    break;
		case COND_1101:    instr_type = FMOVFSLE;     break;
		case COND_1110:    instr_type = FMOVFSULE;    break;
		case COND_1111:    instr_type = FMOVFSO;      break;
		default:           instr_type = UNKNOWN_INSTR;      break;
	    }
	    break;
	}

	case OPF_0_XX00_0010: 
	{
	    dest_type = DP_TYPE;
	    switch (iw.cond()) {
		case COND_1000:    instr_type = FMOVFDA;      break;
		case COND_0000:    instr_type = FMOVFDN;      break;
		case COND_0111:    instr_type = FMOVFDU;      break;
		case COND_0110:    instr_type = FMOVFDG;      break;
		case COND_0101:    instr_type = FMOVFDUG;     break;
		case COND_0100:    instr_type = FMOVFDL;      break;
		case COND_0011:    instr_type = FMOVFDUL;     break;
		case COND_0010:    instr_type = FMOVFDLG;     break;
		case COND_0001:    instr_type = FMOVFDNE;     break;
		case COND_1001:    instr_type = FMOVFDE;      break;
		case COND_1010:    instr_type = FMOVFDUE;     break;
		case COND_1011:    instr_type = FMOVFDGE;     break;
		case COND_1100:    instr_type = FMOVFDUGE;    break;
		case COND_1101:    instr_type = FMOVFDLE;     break;
		case COND_1110:    instr_type = FMOVFDULE;    break;
		case COND_1111:    instr_type = FMOVFDO;      break;
		default:           instr_type = UNKNOWN_INSTR;      break;
	    }
	    break;
	}

	case OPF_0_XX00_0011: 
	{
	    dest_type = QP_TYPE;
	    switch (iw.cond()) {
		case COND_1000:    instr_type = FMOVFQA;      break;
		case COND_0000:    instr_type = FMOVFQN;      break;
		case COND_0111:    instr_type = FMOVFQU;      break;
		case COND_0110:    instr_type = FMOVFQG;      break;
		case COND_0101:    instr_type = FMOVFQUG;     break;
		case COND_0100:    instr_type = FMOVFQL;      break;
		case COND_0011:    instr_type = FMOVFQUL;     break;
		case COND_0010:    instr_type = FMOVFQLG;     break;
		case COND_0001:    instr_type = FMOVFQNE;     break;
		case COND_1001:    instr_type = FMOVFQE;      break;
		case COND_1010:    instr_type = FMOVFQUE;     break;
		case COND_1011:    instr_type = FMOVFQGE;     break;
		case COND_1100:    instr_type = FMOVFQUGE;    break;
		case COND_1101:    instr_type = FMOVFQLE;     break;
		case COND_1110:    instr_type = FMOVFQULE;    break;
		case COND_1111:    instr_type = FMOVFQO;      break;
		default:           instr_type = UNKNOWN_INSTR;      break;
	    }
	    if ( instr_type != UNKNOWN_INSTR ) {
		if (throw_fp_exception_other_) {
		    if ( fpDisabled() ) {
			if ( setFpDirtyBitsWhenFpDisabled() )
			    setFpDirtyBits( iw, dest_type );
			    RIESLING_TRAP( FP_DISABLED_TRAP );
		    }
		    // N1 still throws pf_exception_other trap, which has lower priority
		    asPtr_->getFsrRegPtr()->setFTT( FTT_UNIMPLEMENTED_FPOP );
		    RIESLING_TRAP( FP_EXCEPTION_OTHER_TRAP );
		}
		else {
		    RIESLING_TRAP( V9_Trap::illegal_instruction );
		}
	    }
	    break;
	}

	case OPF_1_0000_0001:
	case OPF_1_1000_0001: 
	{
	    dest_type = SP_TYPE;
	    switch (iw.cond()) {
		case COND_1000:    instr_type = FMOVSA;      break;
		case COND_0000:    instr_type = FMOVSN;      break;
		case COND_1001:    instr_type = FMOVSNE;     break;
		case COND_0001:    instr_type = FMOVSE;      break;
		case COND_1010:    instr_type = FMOVSG;      break;
		case COND_0010:    instr_type = FMOVSLE;     break;
		case COND_1011:    instr_type = FMOVSGE;     break;
		case COND_0011:    instr_type = FMOVSL;      break;
		case COND_1100:    instr_type = FMOVSGU;     break;
		case COND_0100:    instr_type = FMOVSLEU;    break;
		case COND_1101:    instr_type = FMOVSCC;     break;
		case COND_0101:    instr_type = FMOVSCS;     break;
		case COND_1110:    instr_type = FMOVSPOS;    break;
		case COND_0110:    instr_type = FMOVSNEG;    break;
		case COND_1111:    instr_type = FMOVSVC;     break;
		case COND_0111:    instr_type = FMOVSVS;     break;
		default:           instr_type = UNKNOWN_INSTR;      break;
	    }
	    break;
	}

	case OPF_1_0000_0010:
	case OPF_1_1000_0010: 
	{
	    dest_type = DP_TYPE;
	    switch (iw.cond()) {
		case COND_1000:    instr_type = FMOVDA;      break;
		case COND_0000:    instr_type = FMOVDN;      break;
		case COND_1001:    instr_type = FMOVDNE;     break;
		case COND_0001:    instr_type = FMOVDE;      break;
		case COND_1010:    instr_type = FMOVDG;      break;
		case COND_0010:    instr_type = FMOVDLE;     break;
		case COND_1011:    instr_type = FMOVDGE;     break;
		case COND_0011:    instr_type = FMOVDL;      break;
		case COND_1100:    instr_type = FMOVDGU;     break;
		case COND_0100:    instr_type = FMOVDLEU;    break;
		case COND_1101:    instr_type = FMOVDCC;     break;
		case COND_0101:    instr_type = FMOVDCS;     break;
		case COND_1110:    instr_type = FMOVDPOS;    break;
		case COND_0110:    instr_type = FMOVDNEG;    break;
		case COND_1111:    instr_type = FMOVDVC;     break;
		case COND_0111:    instr_type = FMOVDVS;     break;
		default:           instr_type = UNKNOWN_INSTR;      break;
	    }
	    break;
	}

	case OPF_1_0000_0011:
	case OPF_1_1000_0011: 
	{
	    dest_type = QP_TYPE;
	    switch (iw.cond()) {
		case COND_1000:    instr_type = FMOVQA;      break;
		case COND_0000:    instr_type = FMOVQN;      break;
		case COND_1001:    instr_type = FMOVQNE;     break;
		case COND_0001:    instr_type = FMOVQE;      break;
		case COND_1010:    instr_type = FMOVQG;      break;
		case COND_0010:    instr_type = FMOVQLE;     break;
		case COND_1011:    instr_type = FMOVQGE;     break;
		case COND_0011:    instr_type = FMOVQL;      break;
		case COND_1100:    instr_type = FMOVQGU;     break;
		case COND_0100:    instr_type = FMOVQLEU;    break;
		case COND_1101:    instr_type = FMOVQCC;     break;
		case COND_0101:    instr_type = FMOVQCS;     break;
		case COND_1110:    instr_type = FMOVQPOS;    break;
		case COND_0110:    instr_type = FMOVQNEG;    break;
		case COND_1111:    instr_type = FMOVQVC;     break;
		case COND_0111:    instr_type = FMOVQVS;     break;
		default:           instr_type = UNKNOWN_INSTR;      break;
	    }
	    break;
	}

	default:
	{
	    if (throw_fp_exception_other_) {
	        if ( fpDisabled() ) {
		    if ( setFpDirtyBitsWhenFpDisabled() )
		        setFpDirtyBits( iw, dest_type );
		    RIESLING_TRAP( FP_DISABLED_TRAP );
		}
		// N1 still throws pf_exception_other trap, which has lower priority
		asPtr_->getFsrRegPtr()->setFTT( FTT_UNIMPLEMENTED_FPOP );
		RIESLING_TRAP( FP_EXCEPTION_OTHER_TRAP );
 	    }
	    else {
	        RIESLING_TRAP( V9_Trap::illegal_instruction );
	    }

	    return true;
	    break;
	}
    }

    if (instr_type == UNKNOWN_INSTR) {
	return false;
    }

    cc_index  =  iw.opf_cc();

//     if (isUnimplementedV9Instruction(iw, instr_type) ||
// 	(iw.get( 18, 18 ) != 0) ||
// 	(cc_index == 0x5) ||
// 	(cc_index == 0x7))
//     {
//         RIESLING_TRAP( V9_Trap::illegal_instruction );
//     }

    if (!throw_fp_exception_other_ && 
	 (isUnimplementedV9Instruction( iw, instr_type ) || iw.fguNonZeroReservedBits())) {
	// other throw illegal_instruction
        RIESLING_TRAP( V9_Trap::illegal_instruction );
    }

    if ( fpDisabled() ) {
        if ( setFpDirtyBitsWhenFpDisabled() )
	  setFpDirtyBits( iw, dest_type );
	RIESLING_TRAP( FP_DISABLED_TRAP );
    }

    if (throw_fp_exception_other_ && 
	(isUnimplementedV9Instruction( iw, instr_type ) || iw.fguNonZeroReservedBits() || (iw.get( 18, 18 ) != 0) ||
(cc_index == 0x5) || (cc_index == 0x7))) {
	// N1 still throws pf_exception_other trap, which has lower priority
	asPtr_->getFsrRegPtr()->setFTT( FTT_UNIMPLEMENTED_FPOP );
	RIESLING_TRAP( FP_EXCEPTION_OTHER_TRAP );
    }

    dont_read_ccs = ( ( instr_type == FMOVFSN ) ||
                      ( instr_type == FMOVFSA ) ||
                      ( instr_type == FMOVFDN ) ||
                      ( instr_type == FMOVFDA ) ||
                      ( instr_type == FMOVFQN ) ||
                      ( instr_type == FMOVFQA ) ||
                      ( instr_type == FMOVSN  ) ||
                      ( instr_type == FMOVSA  ) ||
                      ( instr_type == FMOVDN  ) ||
                      ( instr_type == FMOVDA  ) ||
                      ( instr_type == FMOVQN  ) ||
                      ( instr_type == FMOVQA  ) );

    if ( ! dont_read_ccs ) {

        if ( cc_index == ICC_REG_NUM ) {
            access_decoded_ccs( ICC_ACCESS, &z, &n, &c, &v, READ_ACCESS );
        } else if ( cc_index == XCC_REG_NUM ) {
            access_decoded_ccs( XCC_ACCESS, &z, &n, &c, &v, READ_ACCESS );
        } else {
            access_decoded_fccs( cc_index, &e, &l, &g, &u, READ_ACCESS );
        }
    }

    // Don't need to process operands only to set rounding mode and clear exceptions

    trap_status = fpu_preprocess( iw, instr_type,
                                  qp_dummy, &dp_dummy, &sp_dummy, FP_OP_NONE,
                                  qp_dummy, &dp_dummy, &sp_dummy, FP_OP_NONE );

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    switch ( instr_type ) {
        /***********************************************************************
        *    FMOVFSxxx instructions . . .
        **********************************************************************/
        case FMOVFSNE:   move_reg = l | g | u;              fp_type = SP_TYPE;    break;
        case FMOVFSE:    move_reg = e;                      fp_type = SP_TYPE;    break;
        case FMOVFSN:    move_reg = false;                  fp_type = SP_TYPE;    break;
        case FMOVFSLG:   move_reg = l | g;                  fp_type = SP_TYPE;    break;
        case FMOVFSUL:   move_reg = l | u;                  fp_type = SP_TYPE;    break;
        case FMOVFSL:    move_reg = l;                      fp_type = SP_TYPE;    break;
        case FMOVFSUG:   move_reg = g | u;                  fp_type = SP_TYPE;    break;
        case FMOVFSG:    move_reg = g;                      fp_type = SP_TYPE;    break;
        case FMOVFSU:    move_reg = u;                      fp_type = SP_TYPE;    break;
        case FMOVFSA:    move_reg = true;                   fp_type = SP_TYPE;    break;
        case FMOVFSUE:   move_reg = e | u;                  fp_type = SP_TYPE;    break;
        case FMOVFSGE:   move_reg = e | g;                  fp_type = SP_TYPE;    break;
        case FMOVFSUGE:  move_reg = e | g | u;              fp_type = SP_TYPE;    break;
        case FMOVFSLE:   move_reg = e | l;                  fp_type = SP_TYPE;    break;
        case FMOVFSULE:  move_reg = e | l | u;              fp_type = SP_TYPE;    break;
        case FMOVFSO:    move_reg = e | l | g;              fp_type = SP_TYPE;    break;
        /***********************************************************************
        *    FMOVFDxxx instructions . . .
        **********************************************************************/
        case FMOVFDNE:   move_reg = l | g | u;              fp_type = DP_TYPE;    break;
        case FMOVFDE:    move_reg = e;                      fp_type = DP_TYPE;    break;
        case FMOVFDN:    move_reg = false;                  fp_type = DP_TYPE;    break;
        case FMOVFDLG:   move_reg = l | g;                  fp_type = DP_TYPE;    break;
        case FMOVFDUL:   move_reg = l | u;                  fp_type = DP_TYPE;    break;
        case FMOVFDL:    move_reg = l;                      fp_type = DP_TYPE;    break;
        case FMOVFDUG:   move_reg = g | u;                  fp_type = DP_TYPE;    break;
        case FMOVFDG:    move_reg = g;                      fp_type = DP_TYPE;    break;
        case FMOVFDU:    move_reg = u;                      fp_type = DP_TYPE;    break;
        case FMOVFDA:    move_reg = true;                   fp_type = DP_TYPE;    break;
        case FMOVFDUE:   move_reg = e | u;                  fp_type = DP_TYPE;    break;
        case FMOVFDGE:   move_reg = e | g;                  fp_type = DP_TYPE;    break;
        case FMOVFDUGE:  move_reg = e | g | u;              fp_type = DP_TYPE;    break;
        case FMOVFDLE:   move_reg = e | l;                  fp_type = DP_TYPE;    break;
        case FMOVFDULE:  move_reg = e | l | u;              fp_type = DP_TYPE;    break;
        case FMOVFDO:    move_reg = e | l | g;              fp_type = DP_TYPE;    break;
        /***********************************************************************
        *    FMOVFQxxx instructions . . .
        **********************************************************************/
        case FMOVFQNE:   move_reg = l | g | u;              fp_type = QP_TYPE;    break;
        case FMOVFQE:    move_reg = e;                      fp_type = QP_TYPE;    break;
        case FMOVFQN:    move_reg = false;                  fp_type = QP_TYPE;    break;
        case FMOVFQLG:   move_reg = l | g;                  fp_type = QP_TYPE;    break;
        case FMOVFQUL:   move_reg = l | u;                  fp_type = QP_TYPE;    break;
        case FMOVFQL:    move_reg = l;                      fp_type = QP_TYPE;    break;
        case FMOVFQUG:   move_reg = g | u;                  fp_type = QP_TYPE;    break;
        case FMOVFQG:    move_reg = g;                      fp_type = QP_TYPE;    break;
        case FMOVFQU:    move_reg = u;                      fp_type = QP_TYPE;    break;
        case FMOVFQA:    move_reg = true;                   fp_type = QP_TYPE;    break;
        case FMOVFQUE:   move_reg = e | u;                  fp_type = QP_TYPE;    break;
        case FMOVFQGE:   move_reg = e | g;                  fp_type = QP_TYPE;    break;
        case FMOVFQUGE:  move_reg = e | g | u;              fp_type = QP_TYPE;    break;
        case FMOVFQLE:   move_reg = e | l;                  fp_type = QP_TYPE;    break;
        case FMOVFQULE:  move_reg = e | l | u;              fp_type = QP_TYPE;    break;
        case FMOVFQO:    move_reg = e | l | g;              fp_type = QP_TYPE;    break;
        /***********************************************************************
        *    FMOVSxxx instructions . . .
        **********************************************************************/
        case FMOVSE:     move_reg = z;                      fp_type = SP_TYPE;    break;
        case FMOVSCS:    move_reg = c;                      fp_type = SP_TYPE;    break;
        case FMOVSNE:    move_reg = ! z;                    fp_type = SP_TYPE;    break;
        case FMOVSCC:    move_reg = ! c;                    fp_type = SP_TYPE;    break;
        case FMOVSN:     move_reg = false;                  fp_type = SP_TYPE;    break;
        case FMOVSLE:    move_reg = z | ( n ^ v );          fp_type = SP_TYPE;    break;
        case FMOVSL:     move_reg = n ^ v;                  fp_type = SP_TYPE;    break;
        case FMOVSLEU:   move_reg = c | z;                  fp_type = SP_TYPE;    break;
        case FMOVSNEG:   move_reg = n;                      fp_type = SP_TYPE;    break;
        case FMOVSVS:    move_reg = v;                      fp_type = SP_TYPE;    break;
        case FMOVSA:     move_reg = true;                   fp_type = SP_TYPE;    break;
        case FMOVSG:     move_reg = ! ( z | ( n ^ v ) );    fp_type = SP_TYPE;    break;
        case FMOVSGE:    move_reg = ! ( n ^ v );            fp_type = SP_TYPE;    break;
        case FMOVSGU:    move_reg = ! ( c | z );            fp_type = SP_TYPE;    break;
        case FMOVSPOS:   move_reg = ! n;                    fp_type = SP_TYPE;    break;
        case FMOVSVC:    move_reg = ! v;                    fp_type = SP_TYPE;    break;
        /***********************************************************************
        *    FMOVDxxx instructions . . .
        **********************************************************************/
        case FMOVDE:     move_reg = z;                      fp_type = DP_TYPE;    break;
        case FMOVDCS:    move_reg = c;                      fp_type = DP_TYPE;    break;
        case FMOVDNE:    move_reg = ! z;                    fp_type = DP_TYPE;    break;
        case FMOVDCC:    move_reg = ! c;                    fp_type = DP_TYPE;    break;
        case FMOVDN:     move_reg = false;                  fp_type = DP_TYPE;    break;
        case FMOVDLE:    move_reg = z | ( n ^ v );          fp_type = DP_TYPE;    break;
        case FMOVDL:     move_reg = n ^ v;                  fp_type = DP_TYPE;    break;
        case FMOVDLEU:   move_reg = c | z;                  fp_type = DP_TYPE;    break;
        case FMOVDNEG:   move_reg = n;                      fp_type = DP_TYPE;    break;
        case FMOVDVS:    move_reg = v;                      fp_type = DP_TYPE;    break;
        case FMOVDA:     move_reg = true;                   fp_type = DP_TYPE;    break;
        case FMOVDG:     move_reg = ! ( z | ( n ^ v ) );    fp_type = DP_TYPE;    break;
        case FMOVDGE:    move_reg = ! ( n ^ v );            fp_type = DP_TYPE;    break;
        case FMOVDGU:    move_reg = ! ( c | z );            fp_type = DP_TYPE;    break;
        case FMOVDPOS:   move_reg = ! n;                    fp_type = DP_TYPE;    break;
        case FMOVDVC:    move_reg = ! v;                    fp_type = DP_TYPE;    break;
        /***********************************************************************
        *    FMOVQxxx instructions . . .
        **********************************************************************/
        case FMOVQE:     move_reg = z;                      fp_type = QP_TYPE;    break;
        case FMOVQCS:    move_reg = c;                      fp_type = QP_TYPE;    break;
        case FMOVQNE:    move_reg = ! z;                    fp_type = QP_TYPE;    break;
        case FMOVQCC:    move_reg = ! c;                    fp_type = QP_TYPE;    break;
        case FMOVQN:     move_reg = false;                  fp_type = QP_TYPE;    break;
        case FMOVQLE:    move_reg = z | ( n ^ v );          fp_type = QP_TYPE;    break;
        case FMOVQL:     move_reg = n ^ v;                  fp_type = QP_TYPE;    break;
        case FMOVQLEU:   move_reg = c | z;                  fp_type = QP_TYPE;    break;
        case FMOVQNEG:   move_reg = n;                      fp_type = QP_TYPE;    break;
        case FMOVQVS:    move_reg = v;                      fp_type = QP_TYPE;    break;
        case FMOVQA:     move_reg = true;                   fp_type = QP_TYPE;    break;
        case FMOVQG:     move_reg = ! ( z | ( n ^ v ) );    fp_type = QP_TYPE;    break;
        case FMOVQGE:    move_reg = ! ( n ^ v );            fp_type = QP_TYPE;    break;
        case FMOVQGU:    move_reg = ! ( c | z );            fp_type = QP_TYPE;    break;
        case FMOVQPOS:   move_reg = ! n;                    fp_type = QP_TYPE;    break;
        case FMOVQVC:    move_reg = ! v;                    fp_type = QP_TYPE;    break;
	default:
	{
	    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
	    break;
	}
    }


    read_src2_reg( iw, fp_type, qp_value, &dp_value, &sp_value, &trap_status );

    if (trap_status != NO_TRAP) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    }

    trap_status = fpu_postprocess( true, iw, instr_type,
                                   FP_OP_NONE, FP_OP_NONE, 0, FP_OP_NONE, UNKNOWN_TYPE,
                                   qp_dummy, &dp_dummy, &sp_dummy ).trap_status;

    if ( trap_status != NO_TRAP ) {
	BasicTrap trapObject( trap_status );
	throw trapObject;
    } else {
	write_dest_reg( iw, qp_value, &dp_value, &sp_value, move_reg, fp_type, &trap_status );
	if ( trap_status != NO_TRAP ) {
	    BasicTrap trapObject( trap_status );
	    throw trapObject;
	}
    }

    INC_PC_AND_NPC();

    return true;
}


fp_result Fpu::fpu_postprocess(
    bool  		simd_fpop,
    InstructionWord    &iw,
    instr_e             instr_type,
    fp_op_type          src1_fpop_type,
    fp_op_type          src2_fpop_type,
    int                 Er,
    fp_op_type          rd_fpop_type,
    enum op_reg_type_e  dest_type,
    uint64_t		rd_qp_value[2],
    uint64_t		*rd_dp_value,
    uint32_t		*rd_sp_value )
{
    fp_result             result = { FP_NONE, NO_TRAP };

    return result;
}

void Fpu::fpDirtyBitsWhenFpDisabled( bool value )
{
    fpDirtyBitsWhenFpDisabled_ = value;
}

bool Fpu::setFpDirtyBitsWhenFpDisabled()
{
    return fpDirtyBitsWhenFpDisabled_;
}

void Fpu::snapshot( SS_SnapShot &ss, const char *prefix )
{
	// bool throw_fp_exception_other_;
        // bool pstate_tct_enabled_;                         // Transfer Control Trap enabled
        // bool pstate_tct_launch_;                          // Signal back to instruction emulator
        // V9_ArchState  *asPtr_;                        // Temporary location for the pointer to Architectural State object
        // FloatRegisterFile  *fregPtr_;                     // Temporary location for the pointer to FloatRegisterFile object
	// bool fpDirtyBitsWhenFpDisabled_;
    sprintf(ss.tag,"%s.throwFpExcOther",prefix); ss.val(&throw_fp_exception_other_);
    sprintf(ss.tag,"%s.pstateTctEnabled",prefix); ss.val(&pstate_tct_enabled_);
    sprintf(ss.tag,"%s.pstateTctLaunched",prefix); ss.val(&pstate_tct_launch_);
    sprintf(ss.tag,"%s.fpDirtyBitsWhenFpDisabled",prefix); ss.val(&fpDirtyBitsWhenFpDisabled_);
}
